Forum: Mikrocontroller und Digitale Elektronik MAX31865 mit STM32 auswerten


von Jakob (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
mir ist bekannt das es zu der Thematik einige Beispiele gibt, jedoch 
komme ich auch damit nicht auf den Fehler.

Folgende Hardware:

StM32f100RB6 Discovery
MAX31865 
(http://www.ebay.de/itm/PT100-PT1000-temperature-converter-SPI-digital-output-Arduino-MAX31865-from-EU-/171701993176)

Das Problem ist das der MAX auf keinen Befehl antwortet. MISO= 0xFF

So sieht die SPI Kommunikation aus (Bild): 0x80 (Write Mode) 0x83 
(Config) 0x20 (Start 1Shot conversion) nach einem delay von 200ms dann 
0x00 (Read Mode) 0x00 (Starte lesen Register MSB 0x01)

Die Verdrahtung sollte passen!
Der MAX liegt an der STM32 3V3 Spannungsversorgung, jedoch messe ich 
hier 2,96 V (nach Datenblatt 3-3.3-3.6). Das sollte aber nicht das 
Problem sein. Die Klemmen sind auf 2 Wire gebrückt und mit einen PT100 
versehen.

Der SPI Takt sollte mit einen Prescaler von 32 definitiv unter 5 Mhz 
liegen.

MAX31865 supports SPI Mode 1 und 3. Habe Mode 3 CPOL=1, CPHA=1

Die SPI config ist vom http://www.diller-technologies.de/stm32.html#spi 
übernommen.

Da ich mich zum ersten mal mit dem SPI Bus und co beschäftige könnte da 
natürlich ein einfach Fehler vorliegen den ich nicht sehe.

Vllt hat jemand von euch noch eine Idee was es sein könnte.
1
Hier noch dazu die main.c
2
3
Danke schon mal!
4
5
/*******************************************************************************
6
 PIN OVERVIEW:
7
8
 GPIO A    USED BY
9
 0      /
10
 1      /
11
 2      /
12
 3      /
13
 4
14
 5      SPI sck
15
 6      SPI miso
16
 7      SPI mosi
17
 8      CS
18
 9      USART tx 
19
 10      USART rx 
20
 11      
21
 12      
22
 13
23
 14
24
 15
25
 **                          CONFIGURATION PARAMETERS                         **
26
 *******************************************************************************/
27
28
//#define DRDY_IC1 10
29
//#define DRDY_IC2 11
30
#define REFERENCE_RESISTOR 400
31
#define PT_RESISTANCE 100
32
#define IC1 11
33
#define IC2 12
34
35
/**
36
 * Configuration of the MAX31865 from MSB to LSB:
37
 * BIT      FUNCTION            ASSIGNMENT
38
 *  7       VBIAS               0=OFF            1=ON
39
 *  6       Conversion Mode     0=Normally OFF   1=AUTO
40
 *  5       1-Shot              0= -             1=1-Shot
41
 *  4       3-Wire              0=2- or 4-Wire   1=3-wire
42
 * 3,2      Faultdetection      set both to 0
43
 *  1       Fault Status Clear  set to 1
44
 *  0       50/60Hz filter      0=60Hz           1=50Hz
45
 */
46
#define MAX31865_CONFIG 0b10000011
47
48
//*******************************************************************************
49
#include "stm32f10x_conf.h"
50
#include "spi.h"
51
#include "stm32_ub_systick.h"
52
#include "uart.h"
53
#include "stdio.h"
54
55
#define CONFIGURATION_REGISTER 0x00
56
#define RTD_MSB_REGISTER 0x01
57
#define RTD_LSB_REGISTER 0x02
58
#define HIGH_FAULT_THRESHOLD_MSB_REGISTER 0x03
59
#define HIGH_FAULT_THRESHOLD_LSB_REGISTER 0x04
60
#define LOW_FAULT_THRESHOLD_MSB_REGISTER 0x05
61
#define LOW_FAULT_THRESHOLD_LSB_REGISTER 0x06
62
#define FAULT_STATUS_REGISTER 0x07
63
64
#define READ_MODE 0x00
65
#define WRITE_MODE 0x80
66
#define START_1_SHOT 0x20
67
//#define MAX31865_CONFIG 0b10010011
68
69
int main(void)
70
{
71
72
  GPIO_InitTypeDef GPIO_InitStructure;
73
  NVIC_InitTypeDef NVIC_InitStructure;
74
  SPI_InitTypeDef SPI_InitStructure;
75
76
  SystemInit();
77
  UB_Systick_Init();
78
  usart_init();
79
80
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_SPI1, ENABLE);
81
    /* Initialize LED which connected to PC6,9, Enable the Clock*/
82
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
83
    /* Configure the GPIO_LED pin */
84
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_6;
85
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
86
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
87
    GPIO_Init(GPIOC, &GPIO_InitStructure);
88
89
    GPIO_WriteBit(GPIOC,GPIO_Pin_9,Bit_SET);
90
    GPIO_WriteBit(GPIOC,GPIO_Pin_6,Bit_SET);
91
    UB_Systick_Pause_ms(3);
92
93
    GPIO_WriteBit(GPIOC,GPIO_Pin_8,Bit_SET);
94
95
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
96
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
97
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
98
  GPIO_Init(GPIOA, &GPIO_InitStructure);
99
100
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
101
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
102
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
103
  GPIO_Init(GPIOA, &GPIO_InitStructure);
104
105
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
106
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
107
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
108
  GPIO_Init(GPIOA, &GPIO_InitStructure);
109
110
  GPIO_WriteBit(GPIOA, GPIO_Pin_8, SET);
111
112
  NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
113
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
114
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
115
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
116
  NVIC_Init(&NVIC_InitStructure);
117
118
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
119
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
120
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
121
  SPI_InitStructure.SPI_CRCPolynomial = 7;
122
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
123
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
124
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
125
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
126
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
127
  SPI_Init(SPI1, &SPI_InitStructure);
128
129
  SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);
130
131
  SPI_Cmd(SPI1, ENABLE);
132
133
  spi_create(SPI1, GPIOA, GPIO_Pin_8);
134
135
  spi_writeByte(WRITE_MODE);
136
  spi_writeByte(MAX31865_CONFIG);
137
  spi_writeByte(START_1_SHOT);
138
  UB_Systick_Pause_ms(200);
139
140
  //spi_writeByte(READ_MODE);
141
  spi_writeByte(0x00);
142
  spi_writeByte(0x01);
143
144
  //spi_writeTwoBytes(0x12,0x34);
145
  //spi_writeTwoBytes(0x00,0x00);
146
  //spi_writeTwoBytes(READ_MODE,0x00);
147
  //uint8_t value=spi_receivebyte();
148
149
  //char buffer[22];
150
151
152
  //sprintf(buffer,"%s%d%s","received SPI value ",value,"%n");
153
154
  //UARTSend(buffer,sizeof(buffer));
155
156
  return 0;
157
}

von Jakob (Gast)


Lesenswert?

keiner eine Idee?

von hp-freund (Gast)


Lesenswert?

Nö.

Ich kenne den IC nicht. Aber hast Du dir den Sourcecode angesehen den 
der Verkäufer anbietet? Ist zwar für Ard***o aber der logische Ablauf 
sollte zu erkennen sein.

von JJ (Gast)


Lesenswert?

Probier mal mit (siehe auch Seite 13 / Punkt 1-Short(D5) ):

1. 0x80 (Write Mode) 0x81 (Config)
2. Delay 1 ms + 10.5 Tau
3. 0x80 (Write Mode) 0xA1 (Config)
4. Check DRDY oder warte min. 62,5 ms
5. Ergebnis ablesen


Gruß

JJ

von Jakob (Gast)


Angehängte Dateien:

Lesenswert?

Leider ohne Erfolg!

Tau= R*C
Tau= 400*100nF
10.5Tau=400*100nF*10.5 => 420us+1ms

Das delay dann auf 2ms. Genauer lässt es meine Delay funktion nicht zu.
1
  spi_writeByte(WRITE_MODE);
2
  spi_writeByte(0x81);
3
  UB_Systick_Pause_ms(2);
4
5
  //spi_writeByte(READ_MODE);
6
  spi_writeByte(0x80);
7
  spi_writeByte(0xA1);
8
  UB_Systick_Pause_ms(70);
9
10
  spi_writeByte(READ_MODE);
11
  spi_writeByte(RTD_MSB_REGISTER);

Im Logic Analyzer sieht man auch dann die Delays 2ms => 1.886ms 70ms=> 
69.96ms

Zur Fehlereingrenzung werde ich sobald das Netzteil eintrifft nochmal 
mit korrekten 3.3V den IC versorgen.

Trotzdem Danke JJ & hp-Freund

von Jakob (Gast)


Lesenswert?

Also irgwie bekommt der MAX31865 die cfg nicht. Der Data ready pin ist 
permanent auf high (3V). Den MISO Bus mal GND legen erhält man auch eine 
0x00.

von hp-freund (Gast)


Lesenswert?

Bist Du eigentlich sicher das z.B. zwischen den:
 0x80 (Write Mode) 0x81 (Config)
ein CS=H sein darf?

Hast Du versucht die 16bit am Stück zu senden?

von hp-freund (Gast)


Lesenswert?

Ein Blick ins Datenblatt zeigt das auch bei read und write kein CS=H 
dazwischen sein darf...

von Jakob (Gast)


Lesenswert?

Das hab ich heute herausgefunden! Jetzt klappt es. Zwischen R/W Mode und 
Adresse darf kein CS high sein.

Trotzdem Danke

von Brian B. (brian_b)


Lesenswert?

can you post your final code that you got working? did you set CS to low 
in between the Read / Write

von sachin singh (Gast)


Lesenswert?

Same Problem....my read always returns 255
#define MAX_CS GPIO_Pin_0 // Port B
#define MAX_RDY GPIO_Pin_1 // Port B - RDY = 0 -> Data Ready to be 
Obtained
#define Read_Config 0x00
#define Read_RTD_MSB 0x01
#define Read_RTD_LSB 0x02 // LSB 0Th Bit = Error
#define Read_Threshold_High_MSB 0x03  // High Threshold = 212 Ohm = 300 
Degree C
#define Read_Threshold_High_LSB 0x04
#define Read_Threshold_Low_MSB 0x05
// Low Threshold = 100 Ohm = 0 Degree C
#define Read_Threshold_Low_LSB 0x06
#define Read_Fault 0x07

// Upto Index 20, T = Index x 10......Item Count = 25
// 20 and More Delta = 25 Degree in Look Up Table ( 0 - 300 )
unsigned short LookUptable[] = { 
8192,8512,8830,9148,9465,9781,10096,10410,10723,11035,11346 
,11657,11966,
    12274,12582,12888,13194,13498,13802,14104,14406,15156,15901,16639,17371 
};

int main()
{
  SPI2Setup();
  MAX_31685_Write_Byte( Read_Config , 0xD1 );
// Init => Config Reg = 1101 0001 = D1
  Delay(1,5); //  Init Time > 2 mili Sec
  // set Limits = High and Low Threshold = Max / Min Resistence
  MAX_31685_Write_Byte( Read_Threshold_High_MSB, 0xFF ); // 00
  MAX_31685_Write_Byte( Read_Threshold_High_LSB, 0xFF );
// 0xD4 - High Th = 212 Ohm
  MAX_31685_Write_Byte( Read_Threshold_Low_MSB, 0x00 ); // 00
  MAX_31685_Write_Byte( Read_Threshold_Low_LSB, 0x00 );
 // 0x64 - Low Th = 100 Ohm

  unsigned short ADCCode = 0x00 ;
  float Temp = 0x00 ;
  unsigned char error = 0x00 ;
  unsigned char ConfigReg = MAX_31685_Read_Byte(Read_Config);
  while(1)
  {
    error = MAX_31685_ReadADC(&ADCCode) ; // error = 255 ALWAYS
    if( error ) // Return Fault Reg + Reset error
    {
      MAX_31685_Write_Byte( Read_Config , 0x82 );
// Reset => Config = 1000 0010 = 82
      Delay(1,5);
      MAX_31685_Write_Byte( Read_Config , 0xD1 );
// Init  == Config = 1101 0001 = D1
      Delay(1,5); // Chip Init Time > 2 Mili Sec
    }
    else
       Temp = ADC_TO_Temp(ADCCode);
  }
  return 1 ;
}
float ADC_TO_Temp(unsigned short ADCCode) // Not Tested
{
  float Temp = 0 ;
  unsigned char Index ;
  for( Index = 24 ; Index >= 0 ; Index--)
    if( ADCCode >= LookUptable[Index] )
      break ;
  if ( Index <= 19 )        // Y = mX + C
    Temp = (Temp *10) + ( 10 /(float)(  LookUptable[Index + 1] - 
LookUptable[Index])) * ADCCode ;
  else
    Temp = 200 + (25 * ( Index - 20)) + ( 25 /(float)( 
LookUptable[Index + 1] - LookUptable[Index])) * ADCCode ;
  return Temp ;
}
unsigned char MAX_31685_ReadADC(unsigned short* ADCCode)
{
  unsigned char error = 0 ; // No Error
  *ADCCode = 0 ;
  unsigned char LSB  = MAX_31685_Read_Byte(Read_RTD_LSB);
  if( LSB & 0x01 )
  {
      error  = MAX_31685_Read_Byte(Read_Fault);
      return error ;  // No Fault Detection Cycle
  } // If No Error

  unsigned char MSB  = MAX_31685_Read_Byte(Read_RTD_MSB);
  *ADCCode = ( MSB << 7 ) | ( LSB >> 1 ); // 15 Bit ADC
  // = (( MSB << 8 ) | LSB )  >> 1 ; // Same
  return error ;
}

void MAX_31685_Write_Byte(unsigned char address, unsigned char byte)
{
  address |= 0x80 ;  // Write Address = Read | 0x80
  GPIO_ResetBits(GPIOB, MAX_CS);
  Delay(0,5); // 5 Micro sec
  SPI2_SendBye(address); // 1st Address
  SPI2_SendBye(byte);    // 2nd Data
  Delay(0,5);
  GPIO_SetBits(GPIOB, MAX_CS);
  Delay(0,5);
}

unsigned char MAX_31685_Read_Byte(unsigned char address)
{
  GPIO_ResetBits(GPIOB, MAX_CS);
  Delay(0,5);
  SPI2_SendBye(address); // 1st Address
  unsigned char byte = SPI2_ReadByte(); // 2nd Data
  Delay(0,5);
  GPIO_SetBits(GPIOB, MAX_CS);
  Delay(0,5);
  return byte ;
}

void SPI2Setup(void)
{
  RCC->APB1ENR |= ( 1 << 14 ) ; // SPI2
  RCC->APB2ENR |=  ( 1 << 0 ) |  ( 1 << 3 ); // AFIO  GPIOB

  // PB 0 = Chip Select
  GPIO_InitTypeDef GpioPin;
  GpioPin.GPIO_Pin = GPIO_Pin_0 ; // MAX_CS
  GpioPin.GPIO_Speed = GPIO_Speed_10MHz ;
  GpioPin.GPIO_Mode = GPIO_Mode_Out_PP ; // CS = DO = Out Push Pull
  GPIO_Init(GPIOB, &GpioPin);
  GPIO_SetBits(GPIOB, MAX_CS); // CS = High

  // PB_13 = CLK     PB_14 = MISO       PB_15 = MOSI
  GpioPin.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15 ;
// Clock + MOSI = AF Push Pull
  GpioPin.GPIO_Speed = GPIO_Speed_10MHz;
  GpioPin.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GpioPin);

  GpioPin.GPIO_Pin = GPIO_Pin_14 ; // MISO = Input Pull Up
  GpioPin.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GpioPin);

  GpioPin.GPIO_Pin = GPIO_Pin_1 ; // RDY = Input Pull Down
  GpioPin.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GpioPin);

  SPI_InitTypeDef   MySPI;
  MySPI.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  MySPI.SPI_Mode = SPI_Mode_Master;
  MySPI.SPI_DataSize = SPI_DataSize_8b;
  MySPI.SPI_CPOL = SPI_CPOL_High;   // POL = 1   PHA = 1 =>  MODE 3
  MySPI.SPI_CPHA = SPI_CPHA_2Edge;  // POL = 1   PHA = 1 =>  MODE 3
  MySPI.SPI_NSS = SPI_NSS_Soft;
  MySPI.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8 ;
// 24 / 8 = 3 <= 5 MHz
  MySPI.SPI_CRCPolynomial = 7;
  SPI_Init(SPI2 , &MySPI);
  SPI_Cmd(SPI2 , ENABLE);
}
void SPI2_SendBye(unsigned char byte)
{
  while (  SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_TXE) == RESET ); 
// sending data Wait
  SPI_I2S_SendData(SPI2 , byte);
  while (  SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_RXNE) == RESET ); 
// Wait for data
  byte = SPI_I2S_ReceiveData(SPI2);
// Dummy read to generate clock
}
unsigned char SPI2_ReadByte(void)
{
  while (  SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_TXE) == RESET );
  SPI_I2S_SendData(SPI2 , 0xff);
// Dummy write to generate clock
  while (  SPI_I2S_GetFlagStatus(SPI2 , SPI_I2S_FLAG_RXNE) == RESET );
  return SPI_I2S_ReceiveData(SPI2);
}
// Tim 2 = General Purpose , CNT ARR PSC = 16 Bit in STM32F1
void Tim2_init(unsigned char base) // base = 0 = Micro , base = 1 Mili
{
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
  TIM_TimeBaseInitTypeDef TIM;
  TIM_TimeBaseStructInit(&TIM);
  if(base)
    TIM.TIM_Prescaler = (SystemCoreClock/1000)-1;
// 10 CNT = 1 Mili Sec
  else
    TIM.TIM_Prescaler = (SystemCoreClock/1000000)-1;
// 1 CNT = 1 Micro Sec
  TIM.TIM_Period = 0xFFFF - 1 ; // ARR F4 = 32 Bits , ARR F1 = 16 Bits
  TIM.TIM_ClockDivision = 0;
  TIM.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2,&TIM);
  TIM2->CNT = 0 ; // Reset
  TIM_Cmd(TIM2,ENABLE); // Timer Start
  // STM32F100RB Tim CLK = SystemCoreClock
  // STM32F4 Tim CLK = SystemCoreClock / 2
}

void Delay( unsigned char base , unsigned short Ticks) // 0 = Micro , 1 
= Mili
{
  Tim2_init(base); // Reset during Init
  volatile unsigned short start = TIM2->CNT;
  while((TIM2->CNT - start) <= Ticks);
  // Stop timer
  TIM_Cmd(TIM2,DISABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,DISABLE); // Power Save
}

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.