로그인회원등록 내글장바구니주문조회현재접속자
 상품 검색








 게시판 검색





 
 
회원등록 비번분실


온라인 입금계좌
ㆍ기업은행
ㆍ219-043192-01-028
ㆍ이건영

      거래은행 바로가기
 
 Sensor Applications
아듀이노 응용소스
작성자 avrtools™        
작성일 2018/02/18
첨부#2 i2c_stretch.h_.zip (1KB) (Down:5)
ㆍ추천: 0  ㆍ조회: 136   
  STM32F103C+MCP4725 DDS 1KHz 정현파 발생기
STM32F103C ARM32 기판과 12 비트 DAC MCP4725로 DDS 방식 1KHz 정현파 발생기를 만들었다.
STM32F103C ARM32 기판은 DAC가 없다. ESP32는 DAC가 있지만 생각보다 CPU 속도가 떨어진다.

문제는 주함수에서 작동하지 않고, DAC나 ADC가 모두 타이머 함수에서 자동으로 처리되어야 한다.
주함수는 할일이 많이 있는데, DAC나 ADC에서CPU를  점유하는 만큼 주작업의 성능을 낮추게 된다. 
이 방식의 정현파 DDS 발생기는 주함수가 비어있다. 즉 앞으로 마음대로 활용이 가능하다는 뜻이다.

 ESP32와 STM32
ESP32는 250MHz Dual CPU라는데, 하나만 사용이 가능하고, 나머지는 IDLE 상태다. 속도도 이상하다.
더구나 ADC를 읽어 보면, 옆 CH이 혼입되고, 흔들리고, DMA 함수 불량하고, STM32F103C보다 느리다. 
ESP32는 아뭏튼 생각보다는 CPU 성능이 오르지 않으며, 사용자가 마음대로 쓸 수 없는 종류의 CPU다.

ESP32는 IDLE (사용율 0% CPU CORE가 있음) 상태인 CPU를 User가 전용할 수 있음 대박인데,,,
또한, RTOS 구조도 이상하다. 문제는 main() 함수가 없다, main()은 WiFi나 Bluetooth 함수 안에 있다.
이 문제는 결국 User App이 조금만 시간을 지체하면, 그대로 watchdog reset이 되어 버린다.
영국의 유명한 ESP32 블로거가 이 문제를 espressif 정식 게시판에 문의 했지만 답이 없다.

RTOS는 Ticks 타이머로 I/O를 ticks 간격으로 간헐적으로 읽거나 저장할 뿐이다. 거기에 머무른다?
RTOS 라면 I/O 보조함수를 호출해서 임무를 주기만 하고, 주함수로 바로 빠져 나오지 못한다면,
단순하게 interval timer로 구동하는 multi tasking 가로채기 함수보다 못한 찌지리 상태가 되는데?

 12 비트 DAC MCP4725 조각기판(BOB)
STM32F103C ARM32 기판은 DAC가 없지만, 12 비트 DAC MCP4725를 I2C로 연결하고,
가로채기 함수에서 1.2MHz 고속 I2C로 구동하면, CPU의 부담없이 DDS로 정현파를 발생시킬 수 있다.

 

 STM32의 ADC
STM32F103C CPU의 ADC는 속도가 빠르다. ADC 분주기를 가장 빠른 1.5로 실험하니 파형이 안보인다.
debug 하던 중에 ADC cycles를 71.5로 느리게 하니,1KHz 파형의 반쪽만 화면에 가득차서 넓게 보인다.
아~ ADC가 너무 빠르구나,,, 어쨋든 AD 값이 안정하다면 빠른건 무조건 환영이다 !!!

ADC CH을 4개로 늘리고, DMA buffer도 4배로 키우고, 화면도 buffer의 1/4로 1.5 cycle이 보인다. 
그렇다면 SMP32 CPU의 ADC는 1채널일 때 4*4*4 =64Khz 이므로 50KHz까지는 포착할 수 있는 속도다.
라이브러리 STM32ADC.h도 4ch ADC의 값을 dma_IRQ에서 가로채기 함수로 DMA 전송을 완벽하게 처리한다.
 
참고: STM32의 ADC 전송용 Dma_IRQ 가로채기(interrupt) 처리함수(handller)
실제로, ADC의 변환종료로 timer3가 DMA를 trigger하고, dma가 전송을 끝내면 dma 가로채기가 발생된다.
 
dma 가로채기는 주함수에서 dma 전송이 끝난 버퍼를 2개중 다른 1개로 교체만 한다. (전송 자체가 아님)
주함수는 dma 버퍼가 바뀌면 dma 버퍼에 들어온 데이터로 표시화면에 파형을 그리거나 USB로 전송하면 된다.

#include <STM32ADC.h>
STM32ADC myADC(ADC1);
 
long ticks;
void Dma_IRQ(void)   // interval timer3 interrupt handller for ADC transfer
{
  //digitalWrite(LED, ! digitalRead(LED));
  buff_wr =(buff_wr +1) %2; // end of write to buffer
  ticks++;  // timer for dma transfered
};

 
 4CH 12BIT DMA 전송방식 ADC의 성능확인
 
PA0은 DDS 출력에 연결, PA1은 1/2 VCC에 연결, PA2는 3.3V VCC에 연결, PA3은 GND에 연결했다.
ADC cycles =71.5 이고, ADC를 trigger하는 timer3의 inerval은 1us, timer3 가로채기는 CR2로 설정했다.

 STM32F103C 기판과 MCP4725 모듈을 빵판에 꼽고 점퍼로 연결한 사진
표시기는 OLED SSD1306으로 32F103C DDS 출력을 Scope 함수로 확인중이다.
 


STM32F103C 기판과 MCP4725 모듈을 다음과 같이 연결한다.
핀 1 = MCP4725 VCC ---> CPU기판 3.3V
핀 2 = MCP4725 GND ---> CPU기판 GND
핀 3 = MCP4725 SCL ---> CPU기판 PB6 (I2C-SCL2)
핀 4 = MCP4725 SDA ---> CPU기판 PB7 (I2C-SDA2)
핀 5 = MCP4725 A0 ---> CPU기판 GND 혹은 OPEN (0x62) 혹은 3.3V (0x63)
핀 6 = MCP4725 VO ---> DDS 출력 ---> 스코프로 연결해서 파형을 본다.

핀 5는 MCP4725의 주소를 정하는 A0 핀이며, GND로 연결하거나 OPEN 시키면 0x62로 된다.
DAC가 2개이거나 혹은 다른 I2C 부품과 주소가 중복되면 A0 핀을 3.3V로 연결하면 0x63으로 된다.
 
MCP4725가 1개면 #define DAC_device I2C1로 정의하고,
MCP4725가 2개면 #define DAC_device I2C2로 정의한다.

 고속 I2C 라이브러리
1.2MHZ 고속 I2C Libarary는 i2c_stretch.h 이며, 첨부파일 #2번에 있다.
DDS 발생기 소스 32F103C-DDS-gen-V1.0.ino의 폴더안에 있어야 한다.

고속 I2C 라이브러리 i2c_stretch.h를 사용하는 방법은 다음과 같다
#include <SPI.h>
#include <Wire.h>


#include "i2c_stretch.h" // 고속 I2C object를 코드에 포함시킨다.
#define DAC_device I2C1 // I2C 1번 부품
#define DAC_address 0x62 // I2C 주소는 0x62 (16진)

 1KHz 64 단 정현파 배열함수 value =dac_sine64[x]로 값을 읽는다. (x는 0~63)
정현파 테이블을 128단 이나 256 단으로 사용하지 않은 이유는
CPU 주파수 72MHz를 64KHz나 128KHz DDS 주파수로 만드는 정수는 1125 인데,
2개의 분주기는 정수로만 설정되야 하니까 9*125 혹은 15*75 혹은 25*45 뿐이다. 

const PROGMEM uint16_t dac_sine64[64] =  // 16 비트 상수 64개를 Flash에 저장한다 
{
  2048, 2248, 2447, 2642, 2831, 3013, 3185, 3346,
  3495, 3630, 3750, 3853, 3939, 4007, 4056, 4085,
  4095, 4085, 4056, 4007, 3939, 3853, 3750, 3630,
  3495, 3346, 3185, 3013, 2831, 2642, 2447, 2248,
  2048, 1847, 1648, 1453, 1264, 1082,  910,   749,
   600,   465,  345,   242,  156,    88,    39,    10,
      0,    10,    39,    88,   156,  242,  345,   465,
   600,  749,   910, 1082, 1264, 1453, 1648,  1847
};

 1KHz 128 단 정현파 배열함수 dac_sine128
혹시 정수배로 나누지 않더라도 128단으로 정현파를 만든다면 다음 테이블을 사용할수 있다.
CPU 주파수 72MHz를 128KHz DDS 주파수로 만드는 정수는 562.5 인데,
분주비에 소수점이 있으면 안된다. 0.5를 버리면 97MHz/562 =128.114KHz가 된다,
 
타이머에 몇개의 값이라도 있어야 하므로 16과 35를 분주비로 넣으면,
97MHZ/560 =128.571KHz 가 되고, timer2 인터럽트에서 128단의 DDS 정현파를 만들면,
128.571KHz/128 =1.0045KHz의 정현파가 MCP4752에서 출력된다. 
 
주파수 오차가 있더라도 128단 정현파는 출력회로의 LPF 시정수가 작아서 진폭도 크고 잡음도 적다.
1KHz DDS가 128단 정현파일때, 타이머2 가로채기는 다음과 같이 수정되고 128단 배열함수가 변경되어야 한다.

#define numberof_table (128) // number of dds table
void timer2_interrupt() // sine wave DDS by lookup tabe of 256 bytes
{
  // read 2 bytes, send 1 byte to i2c of MCP4725 DAC and make pointer to next sine table
  i2c_str_sendBytes(DAC_device, dac_sine128[sine_Pos] >>8, dac_sine128[sine_Pos++] & 255);
  sine_Pos %=numberof_table;
};

const PROGMEM uint16_t dac_sine128[128] =
{
  2048, 2148, 2248, 2348, 2447, 2545, 2642, 2737,
  2831, 2923, 3013, 3100, 3185, 3267, 3346, 3423,
  3495, 3565, 3630, 3692, 3750, 3804, 3853, 3898,
  3939, 3975, 4007, 4034, 4056, 4073, 4085, 4093,
  4095, 4093, 4085, 4073, 4056, 4034, 4007, 3975,
  3939, 3898, 3853, 3804, 3750, 3692, 3630, 3565,
  3495, 3423, 3346, 3267, 3185, 3100, 3013, 2923,
  2831, 2737, 2642, 2545, 2447, 2348, 2248, 2148,
  2048, 1947, 1847, 1747, 1648, 1550, 1453, 1358,
  1264, 1172, 1082,   995,  910,  828,   749,   672,
   600,   530,  465,   403,   345,  291,  242,   197,
   156,   120,   88,     61,    39,    22,   10,      2,
     0,       2,   10,     22,    39,    61,   88,   120,
   156,  197,  242,    291,  345,   403,  465,   530,
   600,   672,   749,  828,  910,   995, 1082, 1172,
  1264, 1358, 1453, 1550, 1648, 1747, 1847, 1947
};

 MCP4725의 타이머 2의 초기화 함수

DDS 방식으로 DAC의 64KHz로 출력값을 변경하는 DAC 초기화는 타이머2의 설정이다.

void init_DAC()
{
  nvic_irq_set_priority(NVIC_TIMER2, 0); // 타이머2의 가로채기 우선순위는 0번이다. (최고 수준)
  Timer2.setChannel1Mode(TIMER_OUTPUTCOMPARE); // 타이머2는 CO 모드로 작동한다.
  Timer2.setPrescaleFactor(9); // CPU 주파수 72MHz를 9로 나누어 8MHz를 타이머2에 클럭으로 공급
  Timer2.setOverflow(125); // 타이머2는 125가 되면 리셋한다 (다시 0으로 된다)
  Timer2.setCompare1(1); // 타이머2 가로채기 발생은 1번째 값에서 발생한다. (타이머2 CO를 설정한다)
  Timer2.attachCompare1Interrupt(timer2_interrupt); // 타이머2 CO로 가로채기를 발생한다.
}; // end of init_DAC

 정현파 DDS 발생기 타이머 2 가로채기(interrupt) 처리(handller)함수

 
// 여기서 64개의 정현파 값이 들어있는 배열함수 dac_sine64[64]을 읽어서 DAC로 출력한다.
// 1 cycle의 파형을 64KHz 속도로 64번(step) DAC 출력을 변경한다.

 
#define numberof_table (64) // number of dds table
void timer2_interrupt()
{
  // read 2 bytes, send 1 byte to i2c of MCP4725 DAC and make pointer to next sine table
  i2c_str_sendBytes(DAC_device, dac_sine64[sine_Pos] >>8, dac_sine64[sine_Pos++] & 255);
  sine_Pos %=numberof_table;
}; // end of timer2 interrupt handler

 12 비트 DAC인 MCP4725를 고속 1.2MHz I2C 인터페이스로 연결한다.

// MCP4725 BOB pin (배선 연결방법)
// DAC_SDA1 PB7 <---MCP4725의 SDA를 PB7에 연결한다 
// DAC_SCL1 PB6 <---MCP4725의 SCL을 PB6에 연결한다
 
//#include "i2c_stretch.h" // 고속 I2C object를 코드에 포함시킨다. <--- 위쪽 선언부에 있다.
//#define DAC_device I2C1 // I2C 1번 부품 <--- 위쪽 선언부에 있다.
//#define DAC_address 0x62 // I2C 주소는 0x62 (16진) <--- 위쪽 선언부에 있다.
 
void start_DAC() // I2C PB7과 PB6를 고속 I2C 주파수인 1.2MHz로 초기화 한다
{
  if(i2c_str_IsError(DAC_device) | !i2c_str_PortEnabled(DAC_device))
  {
    //digitalWrite(LED, !digitalRead(LED));
    i2c_str_InitPort(DAC_device, I2C_STRETCH_DIV_1200KHZ);
    i2c_str_StartSending(DAC_device, DAC_address);
  }
}; // end of start_DAC

 아두이노 IDE의 초기화 함수


USBSerial usb; // USB 포트는 직렬포트 1번을 연결한다. (초기화 함수 이전에 있어야 한다)
void setup()
{
   // init usb serial port
  usb.begin(115200); // 직렬포트 1번을 115200 BPS 속도로 USB 포트에 연결한다.
  usb.print(" "); // 새줄(CR+LF) 코드를 USB 포트로 전송한다.

  init_display(); // init 128x64 OLED display SSD1306 (한번만 실행하면 된다)
  init_DAC(); // 12 BIT DAC (0x62)의 설정. (한번만 실행하면 된다)
  start_DAC(); // DAC로 DDS를 작동시킨다. (한번만 실행하면 된다)
}; // end of setup code

 아두이노 IDE의 주함수

void loop()
{
  // 주함수는 다른 처리만 하면 된다. DDS는 타이머 인터럽트로 작동된다.

}; // end of DDS code

 
 참고: SSD1306 라이브러리 사용방법
#include <Adafruit_GFX.h>

#define OLED_SCK  PB13  // SCK
#define OLED_SDI  PB15  // MOSI
#define OLED_RST  255   // VCC
#define OLED_CS   PB12  // CS
#define OLED_DC   PB14  // DC
 
#include <Adafruit_SSD1306_STM32.h>

Adafruit_SSD1306 display(OLED_SDI, OLED_SCK, OLED_DC, OLED_RST,OLED_CS);
 
 참고: SSD1306 초기화 함수
 // init OLED SSD1306
void init_display()
{
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay(); // Clear the buffer.
  display.display();  // display on
 
  display.setTextSize(1); // small text size =(1)
  display.setTextColor(WHITE);  // text color
  display.setCursor(0,0); // start ytext line
 
  display.println("1KHz Sinewave DDS");  // display.write(char)
  display.display();
};

 
 DDS 방식으로 DAC의  1KHz 정현파 출력을 검사중인사진

 
백색은 PB0에 설정한 ADC1 값이고, 황색은 PB1에 설정한 ADC2 값이다.
128step sine wavw인데 필터가 없어 아직은 파형이 울퉁불퉁하다,
이 정도면 작은 LPF로 완벽한 정현파를 만들 수 있다고 본다.


 STM32의 M3-coretex CPU
STM32의 M3-coretex CPU는 M3 계열의 주라인 칩으로 속도도 빠르고, DMA도 잘되고, ADC도 빠르다.
더구나 ADC는 가격대비 높은 성능으로 인근 ch의 ADC값이 혼입없이 빠르고 안정된 값으로 측정된다.
가격 5,600원으로 살 수 있는 STM32 CPU STM32F103C 기판의 성능이 대단하다고 할 수 있다.

USD7.80 배송비 무료, 혹은 7,800원 배송비 별도로 입수할 수 있는 12비트 DAC로 1KHZ DDS가 되고
USD 2.70 배송비 무료, SSD1306 OLED를 연결하면 Scope가 된다.  STM32 세상이 왔다.
이 STM32 CPU는 요즈음 가전기기에서 BLDC 방식의 절전모터를 제어하는데 주로 사용하고 있다.

 STM32F103C 개발기판의 PIN 배치도 (상품명 STM32 Blue-Pill)
  

 이 펌웨어 소스를 응용한 장치의 개발이나, 주문형 펌웨어가 들어간 모듈 주문 받습니다.
 주의 : 이 자료의 무단 복제 및 무단 배포를 금지합니다.
이 프로그램은 무료 소프트웨어로, 신체와 재산 상의 어떤 위험과 손해를 보상하지 않습니다.
이 프로그램은 GNU 무료 소프트웨어 배포규정을 따릅니다.
 AVRTOOLS™

   
윗글 STM32F103C의 ILI9341 ILI9163 TFT-LCD 연결방법
아래글 STM32F103C 기판의 1~8CH ADC DMA 전송
    N         제목    글쓴이 작성일 조회 추천
아듀이노 응용소스 게시판 avrtools™ 2016/02/05 (금) 423 0
41 STM32F103C 12비트 정현파 DDS V2 avrtools™ 2018/03/08 (목) 109 0
40 STM32F103C ILI9341 TFTLCD Scope V2 avrtools™ 2018/03/05 (월) 133 0
39 STM32F103C 32비트 ARM-CPU 2채널 Scope avrtools™ 2018/02/25 (일) 138 0
38 STM32F103C의 ILI9341 ILI9163 TFT-LCD 연결방법 avrtools™ 2018/02/19 (월) 137 0
37 STM32F103C+MCP4725 DDS 1KHz 정현파 발생기 avrtools™ 2018/02/18 (일) 136 0
36 STM32F103C 기판의 1~8CH ADC DMA 전송 avrtools™ 2018/02/17 (토) 136 0
35 STM32F103C 기판의 SSD1306 OLED 구동 avrtools™ 2018/02/16 (금) 132 0
34 STM32F103C ARM32 기판의 독립 IDE 소개 avrtools™ 2018/02/14 (수) 167 0
33 STM32F103C ARM32 기판의 Bootloader 개조 avrtools™ 2018/02/14 (수) 175 0
32 ESP32+OLED 기판과 PWM generator avrtools™ 2018/02/11 (일) 135 0
31 Wemos-Lolin32 Audio FFT Analyzer 제작 avrtools™ 2018/02/07 (수) 141 0
30 DUE SAM3X8E Audio FFT Analyzer 제작 avrtools™ 2018/01/30 (화) 155 0
29 AD5933 LCR-Impedance Analyzer 제작 avrtools™ 2012/03/17 (토) 661 0
28 ESP-01 펌웨어 업그레이드와 WiFi 2 Relay Control avrtools™ 2017/12/24 (일) 133 0
27 ESP12E-devKit로 만드는 WiFi 4 Relay 제어장치 avrtools™ 2017/12/23 (토) 155 0
26 M328-mini로 만드는 Touch 용량검출센서 avrtools™ 2017/12/19 (화) 142 0
25 ESP8266 MQTT Relay Control avrtools™ 2016/03/03 (목) 626 0
24 2 채널 ESP8266 WiFi Switch의 제작 avrtools™ 2016/02/25 (목) 784 0
23 ESP-12E SDK 0.9.5 사용방법 avrtools™ 2016/02/18 (목) 672 0
22 ESP8266 ESP-12E WiFi 센서 서버의 제작 avrtools™ 2016/02/17 (수) 635 0
21 Arduino DS3231 RTC to 5110 LCD avrtools™ 2016/02/16 (화) 643 0
20 ESP8266 Weather Server의 제작 avrtools™ 2016/02/15 (월) 678 0
19 Arduino 온습도 센서 DHT-22 avrtools™ 2016/02/12 (금) 558 0
18 ESP8266 WiFi 펌웨어 업그레이드 avrtools™ 2016/02/11 (목) 878 0
17 Arduion ESP8266 WiFi 설정 방법 avrtools™ 2016/02/10 (수) 859 0
16 Arduino 정전용량식 수분센서의 분석과 제작 avrtools™ 2016/02/07 (일) 477 0
15 Arduino 전극식 수분센서의 분석과 제작 avrtools™ 2016/02/07 (일) 623 0
14 Arduino 정밀 전력계의 ADC avrtools™ 2016/02/02 (화) 903 0
13 Arduino 정밀 전력계의 LPF avrtools™ 2016/02/02 (화) 616 0
12 Ardunio 16비트 ADC Data Logger avrtools™ 2016/01/31 (일) 512 0
11 Arduino AC/DC Power Meter의 제작 avrtools™ 2016/01/29 (금) 1019 0
10 Arduino 교류 역율계(power factor)의 제작 avrtools™ 2016/01/29 (금) 651 0
9 Arduino DUE Pezo-SPeaker LCQ Meter 소스 avrtools™ 2016/01/24 (일) 425 0
8 QTouch ADC 근접검출 스위치 avrtools™ 2016/01/21 (목) 652 0
7 Arduino 음성인식 Speech/Voice Recognition avrtools™ 2013/09/14 (토) 1872 0
6 Arduino Uno로 만드는 3축 CNC avrtools™ 2013/09/10 (화) 2812 0
5 Arduino로 만드는 mySpectral 분광기 avrtools™ 2013/09/04 (수) 2335 0
4 8채널 12비트 ADC MCP3208 오실로스코프 avrtools™ 2012/03/29 (목) 708 0
3 교류저항 (impedance) 측정 AD5933 avrtools™ 2012/03/17 (토) 648 0
2 Arduino DMX512 수신기 제작 avrtools™ 2012/03/15 (목) 3922 0
1 TSL2561 조도 측정기의 제작 avrtools™ 2011/09/11 (일) 2874 0
1

바구니 : 0
 보관함 : 0
오늘뷰 : 0
HOME   |   회사소개   |   제휴안내   |   회사위치   |   서비스이용 약관   |   개인정보 보호정책   |   사이트맵
17015 경기도 용인시 기흥구 동백중앙로16번길 16-25, 508호. 전화 : 031-282-3310
사업자 등록번호 : 697-47-00075 / 대표 : 이건영 / 업태 : 제조업 / 종목 : LED조명, LED전원, 제어장치.
개인정보 관리책임자 : 홈페이지 관리자 . Copyright ⓒ2016 아크레즈 (ACLEDS INC.)
HOME TOP PREVNEXT 0 0 0