Управление ЦАПом AD5761 с помощью контроллера STM32

Mk211
Offline
Зарегистрирован: 19.01.2018

Здравствуйте, возникла такая проблема, не обновляется выход ЦАПа при работе с STM32. Однако при работе с Arduino nano все работает корректно. Код с Arduino был переделан под STM32, подскажите где допустил ошибку.

Ниже приведен код для Arduino и для STM32:

Arduino

#define CMD_NOP              0x0
#define CMD_WR_TO_INPUT_REG       0x1
#define CMD_UPDATE_DAC_REG        0x2
#define CMD_WR_UPDATE_DAC_REG     0x3
#define CMD_WR_CTRL_REG         0x4
#define CMD_NOP_ALT_1         0x5
#define CMD_NOP_ALT_2         0x6
#define CMD_SW_DATA_RESET       0x7
#define CMD_RESERVED          0x8
#define CMD_DIS_DAISY_CHAIN       0x9
#define CMD_RD_INPUT_REG        0xA
#define CMD_RD_DAC_REG          0xB
#define CMD_RD_CTRL_REG         0xC
#define CMD_NOP_ALT_3         0xD
#define CMD_NOP_ALT_4         0xE
#define CMD_SW_FULL_RESET       0xF


#include <SPI.h> // Include the Arduino SPI library

const int ssPin = 10;

static byte SPI_Buff[3];  // read data ???


void setup()
{
  Serial.begin(9600);
  
  pinMode(ssPin, OUTPUT);  // Set the SS pin as an output
  digitalWrite(ssPin, HIGH);  // Set the SS pin HIGH
  SPI.begin();  // Begin SPI hardware
  SPI.setClockDivider(SPI_CLOCK_DIV64);  // Slow down SPI clock
  SPI.setDataMode(SPI_MODE2);
  
  // software reset
  ad5761r_write(CMD_SW_FULL_RESET, 0);

  // read control register
  ad5761r_read(CMD_RD_CTRL_REG);
  ad5761r_read(CMD_RD_CTRL_REG);

  Serial.println("Readback from control register before setting:");
  printRegisterData();

  // write control register
  // [23:21][20][19:16]   [15:11]  [10:9] 8   7   6   5 [4:3] [2:0]
  // |      |  |        |          |    |   |   |   |   |    |      |
  //   X X X  0  0 1 0 0  X X X X X  CV  OVR B2C ETS IRO  PV    RA
  //
  //                                 CV  : Clear voltage selection 00=zero, 01=midscale, 10,11=full scale
  //                                 OVR : 5% overrange 0=5% overrange disabled, 1=5% overrange enabled
  //                                 B2C : Bipolar range 0=DAC input for bipolar range is straight binary coded
  //                                                     1=DAC input for bipolar output range is twos complement code
  //                                 ETS : Thermal shutdown alert 0=does not power down when die temperature exceeds 150degC
  //                                                              1=powers down when die temperature exceeds 150degC
  //                                 IRO : Internal reference 0=off, 1=on
  //                                 PV  : Power up voltage 00=zero scale, 01=midscale, 10,11=full scale
  //                                 RA  : Output range
  //                                       000=-10 to +10
  //                                       001=0 to +10
  //                                       010=-5 to +5
  //                                       011=0 to +5
  //                                       100=-2.5 to +7.5
  //                                       101=-3 to +3
  //                                       110=0 to +16
  //                                       111=0 to +20
  
  ad5761r_write(CMD_WR_CTRL_REG, 0b00000001000);

  // read control register
  ad5761r_read(CMD_RD_CTRL_REG);
  ad5761r_read(CMD_RD_CTRL_REG);

  Serial.println("Readback from control register after setting:");
  printRegisterData();
  
 

}

void printRegisterData() {
  Serial.print("CMD:");
  Serial.print(SPI_Buff[0], HEX);
  
  Serial.print(" DATA:");
  Serial.print(SPI_Buff[1], HEX);
  Serial.print(" ");

  Serial.println(SPI_Buff[2], HEX)
  ;
}

void loop()
{

    ad5761r_write(CMD_WR_UPDATE_DAC_REG, 34000);
    delay(1);
}

void ad5761r_write(uint8_t reg_addr_cmd,
            uint16_t reg_data)
{
  uint8_t data[3];
  delay(1);
  digitalWrite(ssPin, LOW);
  delay(1);

  data[0] = reg_addr_cmd;
  data[1] = (reg_data & 0xFF00) >> 8;
  data[2] = (reg_data & 0x00FF) >> 0;
  for (int i=0; i<3; i++)
  {
    SPI.transfer(data[i]);
  }
  delay(1);
  digitalWrite(ssPin, HIGH);
  delay(1);
}

void ad5761r_read(uint8_t reg_addr_cmd)
{
  delay(1);
  digitalWrite(ssPin, LOW);
  delay(1);
  SPI_Buff[0] = SPI.transfer(reg_addr_cmd);
  SPI_Buff[1] = SPI.transfer(0xFF); 
  SPI_Buff[2] = SPI.transfer(0xFF);
  delay(1);
  digitalWrite(ssPin, HIGH);
}

AD5761.h

#ifndef _AD5761_library_H 
#define _AD5761_library_H 

#define CMD_NOP 0x0 
#define CMD_WR_TO_INPUT_REG 0x1 
#define CMD_UPDATE_DAC_REG 0x2 
#define CMD_WR_UPDATE_DAC_REG 0x3 
#define CMD_WR_CTRL_REG 0x4 
#define CMD_NOP_ALT_1 0x5 
#define CMD_NOP_ALT_2 0x6 
#define CMD_SW_DATA_RESET 0x7 
#define CMD_RESERVED 0x8 
#define CMD_DIS_DAISY_CHAIN 0x9 
#define CMD_RD_INPUT_REG 0xA 
#define CMD_RD_DAC_REG 0xB 
#define CMD_RD_CTRL_REG 0xC 
#define CMD_NOP_ALT_3 0xD 
#define CMD_NOP_ALT_4 0xE 
#define CMD_SW_FULL_RESET 0xF 

#define AD5761_SPI &hspi1 

#define AD5761_CS_SET() (HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)) 
#define AD5761_CS_RESET() (HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)) 

void ad5761_write(uint8_t reg_addr_cmd, uint16_t reg_data); 
void ad5761_writeVoltage(float voltage); 
void ad5761_beginDAC(void); 

#endif

AD5761.c

#include "stm32f1xx_hal.h" 
#include "gpio.h" 
#include "spi.h" 
#include "AD5761_library.h" 
#include "math.h" 


void ad5761_beginDAC(void){ 

ad5761_write(CMD_SW_FULL_RESET, 0); 
ad5761_write(CMD_WR_CTRL_REG, 0x8); 
} 

void ad5761_write(uint8_t reg_addr_cmd, uint16_t reg_data){ 

 uint8_t data[3] = {0}; 
 AD5761_CS_RESET(); 
 AD5761_CS_SET(); 

 data[0] = reg_addr_cmd; 
 data[1] = (reg_data & 0x00FF) » 8; 
 data[2] = (reg_data & 0xFF00) » 0; 
 HAL_SPI_Transmit(AD5761_SPI, data, 3, 10); 
 while(HAL_SPI_GetState(&hspi1)!= HAL_SPI_STATE_READY); 
 AD5761_CS_RESET(); 
} 

void ad5761_writeVoltage(float voltage){ 

 uint16_t outVoltage = ((voltage/2.5)/2)*pow(2,16); 
 ad5761_write(CMD_WR_UPDATE_DAC_REG, outVoltage); 
}

///////////////////////////////////////////////////////

main.c



int main(void) { 

HAL_Init(); 

SystemClock_Config(); 

MX_GPIO_Init(); 
MX_SPI1_Init(); 
ad5761_beginDAC(); 

while (1) { 
 ad5761_write(CMD_WR_UPDATE_DAC_REG, 4558); 
 HAL_Delay(10); 
} 

}

 

b707
Offline
Зарегистрирован: 26.05.2017

STM32 поддерживается ArduinoIDE. так что вы можете взять код для Нано и почти ничего не меняя, скомпилировать его под СТМ32

Хотя я сомневаюсь. что ваш код под Нано работает -я не вижу где в нем обновление данных. Вы в ЛУП только пишете в АЦП. а обратно ничего не читаете

sadman41
Offline
Зарегистрирован: 19.10.2016

Так это не АЦП, а ЦАП вроде как. Читать из него смысла особого нет.

Mk211
Offline
Зарегистрирован: 19.01.2018

Вы наверное оговорились, это ЦАП, а не АЦП, поэтому ничего принимать мне от него не требуется. Код рабочий это 100%, я замерял выход мультиметром). По дата шиту ЦАПа первые 8 бит из 24 отвечают за его конфигурацию, именно они обновляют выход микросхемы. 

 

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Так это не АЦП, а ЦАП вроде как. Читать из него смысла особого нет.

да, сорри, неправильно прочитал вопрос - думал "не обновляются данные с АЦП" :)

ТС - попробуйте скетч для Ардуино Нано скопилировать под СТМ32 в среде Ардуино. В вашем коде вроде нет ничего такого, что требовало бы низкоуровневого программирования для СТМ

 

Mk211
Offline
Зарегистрирован: 19.01.2018

Я пытаюсь освоить STM32, пока, что пошел простым путем с использованием куба, так что ArduinoIDE не вариант.

Mk211
Offline
Зарегистрирован: 19.01.2018

Забыл упомянуть, что выход микросхемы всегда -10В (при работе с stm)

b707
Offline
Зарегистрирован: 26.05.2017

Mk211 пишет:

Я пытаюсь освоить STM32, пока, что пошел простым путем с использованием куба, так что ArduinoIDE не вариант.

Думаю, проблема в иннициализации шины SPI.

К сожалению, я тоже только начинаю осваивать стм32 в кубе. так что единственное, что могу посоветовать - прежде чем работать с неизвестной микросхемой, попробуйте для начала найти в сети любой пример работы с шиной SPI и убедится. что у вас на вашей плате он воспроизводится.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Mk211 пишет:

Я пытаюсь освоить STM32, пока, что пошел простым путем с использованием куба, так что ArduinoIDE не вариант.

А кто Вам сказал, что это простой путь?

Хотите пользоваться кубом вместе с ардуиновскими библиотеками - не забывайте инициализировать этим самым кубом все то, что по умолчанию инициализирует Arduino.

mixail844
Offline
Зарегистрирован: 30.04.2012

ну во первых писать в ардуино в перемешку с HAL прям какой то когнитивный диссонанс вызывет

обычно если пытаться сесть попой на два стула, то падаешь между ними . 

а по делу : если файл Arduino у вас рабочий а файл AD5761.c это библиотека ктороую вы пытаетесь прикрутить 

то между ними есть разница : в файле Arduino в строчке 106 ,вы пин SS только притягиваете к '0' , в файле же AD5761.c  в той же функции в строчках 17-18.вы делаете CS_RESET а потом CS_SET и ваш DAC просто не реагирует на команды .

и точно ли класс SPI в Ардуино по умолчанию заведен на SPI1 ? 

 

b707
Offline
Зарегистрирован: 26.05.2017

mixail844 пишет:

ну во первых писать в ардуино в перемешку с HAL прям какой то когнитивный диссонанс вызывет

насколько я понял ТС, он как раз "вперемешку" ничего не пишет. В его вопросе два разных кода - сначала идет рабочий код для Ардуино Нано. а потом - попытка ТС перенести этот код в Куб для СТМ32

Цитата:
и точно ли класс SPI в Ардуино по умолчанию заведен на SPI1 ?

точно, хотя к вопросу ТС это отношения не имеет :)

mixail844
Offline
Зарегистрирован: 30.04.2012

b707 пишет:

точно, хотя к вопросу ТС это отношения не имеет :)

если по умолчанию(я не знаю,не проверял) класс SPI в ардуино заведен на SPI2 a ТС в библиотеке AD5761 настроил SPI1,а DAC физически подсоединен к SPI2. ничего же работать небудет..

еще вопрос к ТС  : как насторен SPI1 в файле AD5761.c  ? частота spi_clk , размер фрейма ,endianess данных соответствует тому что указано на datasheet AD5761 ? 

mixail844
Offline
Зарегистрирован: 30.04.2012

и еще ,судя по defines в файле AD5761.c CS_RESET у вас выставляет '1'  а CS_SET выставляет '0' ,это для того что бы кого то запутать ? 

b707
Offline
Зарегистрирован: 26.05.2017

mixail844 пишет:

если по умолчанию(я не знаю,не проверял) класс SPI в ардуино заведен на SPI2

по умолчанию в stm32duino класс SPI заведен на SPI1. Это абсолютно точно, можете даже не проверять. Я тут недавно 4 дня потратил на то, чтоб заставить на Блюпилл работать по SPI одновременно TFT экран, тачскрин и RFID :) - так что в нюансах SPI в стм32дуино я покопался основательно :)

Mk211
Offline
Зарегистрирован: 19.01.2018

В кубе инициализировал все правильно, не забыл. SCLK настроен на максимально частоту - 18Mhz, один пакет передает 8 бит. Сначала передается MSB.

Mk211
Offline
Зарегистрирован: 19.01.2018

Мне так удобнее было) Никого запутать не хотел.

b707
Offline
Зарегистрирован: 26.05.2017

Mk211 пишет:

В кубе инициализировал все правильно, не забыл. SCLK настроен на максимально частоту - 18Mhz

а микросхема ЦАП такую скорость тянет?

кстати, если это stm32f103. то макисимум для SPI1 на ней 36 МГц

Mk211
Offline
Зарегистрирован: 19.01.2018

Судя по дата шиту он тянет до 50Mhz. Да это именно она, странно, но куб мне не дал выставить делитель меньше 4.

https://www.st.com/resource/en/datasheet/cd00161566.pdf страница 71.

SPI clock frequency Master mode/Slave mode - 18 MHz 

mixail844
Offline
Зарегистрирован: 30.04.2012

мне кажеться или когда 

 data[0] = reg_addr_cmd;
 data[1] = (reg_data & 0x00FF) >> 8;
 data[2] = (reg_data & 0xFF00) >> 0;

data[1] и data[2] при любом reg_data будут = 0 ?

b707
Offline
Зарегистрирован: 26.05.2017

mixail844 пишет:

мне кажеться или когда 

 data[0] = reg_addr_cmd;
 data[1] = (reg_data & 0x00FF) >> 8;
 data[2] = (reg_data & 0xFF00) >> 0;

data[1] и data[2] при любом reg_data будут = 0 ?

да. похоже :)

В исходном коде, кстати, правильно :)

Mk211
Offline
Зарегистрирован: 19.01.2018

Не заметил, что перенес неправильно. Сейчас переделаю и проверю.

Mk211
Offline
Зарегистрирован: 19.01.2018

Всем спасибо, всё заработало! Невнимательность)