Handmades</center>
 
*
Bem-vindo, Visitante. Por favor faça o Login ou Registro. 29 de Março de 2024, as 06:28:06


Login com nome de usuário, senha e duração da sessão


Páginas: [1]   Ir para o Fundo
  Imprimir  
Autor Tópico: Pitch Shitfter DIY  (Lida 4319 vezes)
Tiago Vulgar
Freqüente
**
Offline Offline

Sexo: Masculino
Mensagens: 346

Obrigado
-Dado: 37
-Recebido: 22


O sonho do careta é a realidade do maluco


« : 03 de Março de 2015, as 22:45:23 »

 Não tive ideia em qual tópico postar, então tô colocando em pedais de efeito (pois acho que nesse mato sai cachorro).
 Estava caçando alguma coisa de Pitch Shifter e encontrei este vídeo. É um Pitch Shifter, só que o cara usa em um MP3 Player.
 Pois bem, no vídeo tem um link que é deste fórum onde o cara postou algumas fotos e detalhes do projeto, também no mesmo fórum eu encontrei o link do projeto (acho que é o original).
 Com um buffer na entrada desse projeto, podemos ter um Pitch Shifter, não?!

O esquema que ele usou foi esse:

Registrado
marcao_cfh
Handmaker
****
Offline Offline

Mensagens: 1.694

Obrigado
-Dado: 158
-Recebido: 414


« Responder #1 : 04 de Março de 2015, as 00:21:00 »

Não sei se o buffer seria necessário, pois tem um 386 na entrada. Mas para usar com a guitarra, seria interessante um mixer para combinar o som original da guitarra com o som processado pelo pitch shifter. Aí tem o custo do PIC e a gravação da programação, essa parte eu não entendo nada...
Registrado
Ledod
Handmaker
****
Offline Offline

Sexo: Masculino
Mensagens: 1.132

Obrigado
-Dado: 17
-Recebido: 139



« Responder #2 : 04 de Março de 2015, as 09:26:32 »

 Tiago

 Interessante! Obrigado por compartilhar!

 Tem um tópico aqui que estávamos discutindo exatamente isso a um bom tempo atrás e incrivelmente, a algumas semanas estava fazendo alguns testes com um STM32F100 (Cortex M3) nesse sentido, para um pitch shifter.

 Eu criei um "ring modulator" ao elevar ao quadrado a amostra do sinal e o resultado sonoro ficou interessante, próximo aos analógicos (para quem gosta do som rs). Mas não era ainda o que pretendia!

 Outro teste foi a qualidade de áudio na conversão ADC/DAC e achei relativamente boa... Possui um mínimo ruído branco de fundo, mas para um efeito bizarro desses, não vai ser notado.

 Não cheguei a implementar o buffer circular com taxas de amostragens diferentes, vou tentar testar neste final de semana e posto os resultados.

 O legal deste microcontrolador e o controlador de DMA, que consegue ler e escrever diretamente da memória para o periférico e vice-versa e o buffer circular já é implementado por hardware! Ou seja, é só conectar o ADC com o DAC pelo DMA e mudar o sampling dos dois timers conectados a eles e ver no que dá!  Cheesy

 Claro, estou um usando um microcontrolador mais poderoso que um PIC, mas a idéia é testar a qualidade disso e se ficar bom, começar a desenvolver algo mais baixo custo (quem sabe uma plaquinha programada e tals...)

 Um abraço!

 Eduardo
Registrado
xformer
Administrator
DIY Freak
******
Offline Offline

Sexo: Masculino
Mensagens: 6.254

Obrigado
-Dado: 71
-Recebido: 2009


e^(i x pi)+1=0


WWW
« Responder #3 : 04 de Março de 2015, as 09:35:26 »

Na Farnell tem:
http://www.farnellnewark.com.br/circuitointegradomicrocontrolador16bit32mhzdi,product,07P9739,4442636.aspx

A R$ 28,77 cada peça.

Como o autor forneceu o arquivo HEX, basta ter um gravador de PIC pra gravar o firmware nele.

O regulador de tensão para 3,3V pode ser outro (LM1117-3,3V por exemplo), não precisa ser o do esquema.
« Última modificação: 04 de Março de 2015, as 09:43:59 por xformer » Registrado

O que se escreve com "facilidade" costuma ser lido com dificuldade pelos outros. Se quiser ajuda em alguma coisa, escreva com cuidado e clareza. Releia sua mensagem postada e corrija os erros.
Tiago Vulgar
Freqüente
**
Offline Offline

Sexo: Masculino
Mensagens: 346

Obrigado
-Dado: 37
-Recebido: 22


O sonho do careta é a realidade do maluco


« Responder #4 : 04 de Março de 2015, as 19:58:11 »

 Ledod, meu conhecimento sobre PIC tende a zero  Embarrassed , porém, estou aprendendo um pouco sobre arduino. Pensei se não daria para usar algum microcontrolador da Atmel no lugar do pic, e claro, configura-lo na linguagem dele.
  Não sei se o cara disponibilizou a linguagem em *.doc, mas se ele não bloqueou o arquivo HEX, talvez dê para convertê-lo em alguma linguagem e decifrar a finalidade da coisa. Talvez seja uma viagem minha mas como o marcao_cfh mencionou em usa-lo combinado com o som original da guitarra como um "harmonizer", então eu pensei se não daria para fazer um harmonizer inteligente igual o PS-6 Harmonist da Boss. Talvez daria para programá-lo com uma referência de frequência e seus múltiplos, assim ele faria a harmonia de acordo com o que programamos. Não sei se é viagem minha, dá p/ fazer isso? Me parece trabalhoso pacas.  Lips Sealed

 
Registrado
xformer
Administrator
DIY Freak
******
Offline Offline

Sexo: Masculino
Mensagens: 6.254

Obrigado
-Dado: 71
-Recebido: 2009


e^(i x pi)+1=0


WWW
« Responder #5 : 04 de Março de 2015, as 21:22:15 »

Ledod, meu conhecimento sobre PIC tende a zero  Embarrassed , porém, estou aprendendo um pouco sobre arduino. Pensei se não daria para usar algum microcontrolador da Atmel no lugar do pic, e claro, configura-lo na linguagem dele.
  Não sei se o cara disponibilizou a linguagem em *.doc, mas se ele não bloqueou o arquivo HEX, talvez dê para convertê-lo em alguma linguagem e decifrar a finalidade da coisa.
 ......
Não sei se é viagem minha, dá p/ fazer isso? Me parece trabalhoso pacas.  Lips Sealed

A partir do HEX esquece. Tem que pegar o arquivo fonte que ele forneceu (pitch_shifter.zip que tem os fontes em C).  A partir dele talvez dê para portar para outro microcontrolador (mesmo assim vai ter um trabalho danado, como você mesmo suspeita). Agora no site onde ele se inspirou (e que você citou) também tem arquivos fontes (em assembly) para os efeitos, e já escritos para microcontroladores AVR.
Registrado

O que se escreve com "facilidade" costuma ser lido com dificuldade pelos outros. Se quiser ajuda em alguma coisa, escreva com cuidado e clareza. Releia sua mensagem postada e corrija os erros.
Ledod
Handmaker
****
Offline Offline

Sexo: Masculino
Mensagens: 1.132

Obrigado
-Dado: 17
-Recebido: 139



« Responder #6 : 05 de Março de 2015, as 11:30:26 »

 Tiago Vulgar

 Fazer engenharia reversa do código a partir do .hex é complicado... Existem softwares que tentam transcrever a sequência de operações, mas para instruções mais específicas, acho difícil sem conhecer qual o compilador utilizado.

 No caso deste software, basicamente você precisará dos conceitos de interrupção bem claros para conseguir fazer algo funcional.

 Basicamente você irá necessitar de dois timers com interrupção e um buffer circular (nada mais é que um array com um ponteiro que volta ao início a cada ciclo) e dois contadores.

 O timer 1 por exemplo, aciona uma interrupção e você lê o valor do ADC e joga no buffer.
 O timer 2 aciona a outra interrupção e você lê o valor contido no bufer e passa para o DAC.

 Cada contador irá informar qual a posição de memória você irá ler na sequência.

 Nesse caso, você terá que dar uma prioridade em qual interrupção acontecerá primeiro, que eu acredito ser do DAC, para evitar problemas de atraso na saída do sinal, na momento em que uma interrupção está lendo e escrevendo na mesma posição do buffer ao mesmo tempo.

 Esse seria um algoritmo básico, sem filtragem das descontinuidades.

 Já um harmonist faz algo mais complexo, ele analisa a nota fundamental tocada e calcula quanto a nota deverá ser alterada para que a escala seja "harmonizada", em um pitch shifter, os intervalos são sempre constantes.

 Precisa criar uma tabela com todas as notas e os intervalos correspondentes.

 Essa circunferência mostra bem as "descontinuidades" entre o Mi-Fá e o Si-Dó, ou seja, nesses pontos os intervalos em semi-tons são diferentes:

 
Registrado
hgamal
Hand MasterMind
*****
Offline Offline

Sexo: Masculino
Mensagens: 3.985

Obrigado
-Dado: 22
-Recebido: 508



« Responder #7 : 05 de Março de 2015, as 11:44:09 »

Eu vi o código e parece simples, não analisei a fundo, mas ele faz referência a seguinte página:

http://elm-chan.org/works/vp/report.html

bem interessante!
Registrado

Deus salva... e o Rock alivia! Ainda está em tempo do Rock 'n' Roll te salvar
kem
DIY Freak
******
Offline Offline

Mensagens: 5.116

Obrigado
-Dado: 91
-Recebido: 787



« Responder #8 : 05 de Março de 2015, as 11:55:41 »

Se tem o codigo pronto pro PIC e é só gravar, qual a intenção de portar para outro microcontrolador?
Registrado

I don't want to die young...
I want to diode!
Tiago Vulgar
Freqüente
**
Offline Offline

Sexo: Masculino
Mensagens: 346

Obrigado
-Dado: 37
-Recebido: 22


O sonho do careta é a realidade do maluco


« Responder #9 : 05 de Março de 2015, as 18:36:47 »

Kem, seria pela simplicidade da linguagem no microcontrolador (no meu modo de ver), se for usar de um arduino a linguagem é bem mais simples do que  assembly, c, c++ (pelo menos até onde vi)!
Registrado
xformer
Administrator
DIY Freak
******
Offline Offline

Sexo: Masculino
Mensagens: 6.254

Obrigado
-Dado: 71
-Recebido: 2009


e^(i x pi)+1=0


WWW
« Responder #10 : 05 de Março de 2015, as 19:16:08 »

Kem, seria pela simplicidade da linguagem no microcontrolador (no meu modo de ver), se for usar de um arduino a linguagem é bem mais simples do que  assembly, c, c++ (pelo menos até onde vi)!

Também não é tão simples como você enxerga. Você precisa comparar as características de cada microcontrolador (o do projeto e o substituto). Os PICs da série 24 são mais sofisticados que os PICs mais comuns (16F e 18F). Primeiro que eles são de 16 bits (os PICs comuns e os AVR são de 8 bits), o que se reflete na capacidade de movimentar e tratar os dados (ex. instruções de multiplicação por hardware de 17 x 17 bits e de divisão 32 por 16 bits, que são muito usadas em processamento digital de sinais). Outra coisa é que o microcontrolador precisa ter bastante RAM pra armazenar os dados da amostragem (esse PIC 24 tem 8kbytes), ter um conversor AD rápido (esse PIC pode fazer até 500k amostragens e conversões por segundo), senão você não vai conseguir gerar o efeito em tempo real e contínuo, com boa banda de frequências.
« Última modificação: 05 de Março de 2015, as 20:58:49 por xformer » Registrado

O que se escreve com "facilidade" costuma ser lido com dificuldade pelos outros. Se quiser ajuda em alguma coisa, escreva com cuidado e clareza. Releia sua mensagem postada e corrija os erros.
Ledod
Handmaker
****
Offline Offline

Sexo: Masculino
Mensagens: 1.132

Obrigado
-Dado: 17
-Recebido: 139



« Responder #11 : 05 de Março de 2015, as 19:19:38 »

 Tiago

 O Arduino, por mais que pareça "simples" é C++ !

 Tente abrir uma biblioteca qualquer (por exemplo, uma de display de LCD) e veja os objetos com os atributos e métodos públicos e privados! Você verá que um simples "lcd.init()" tem muito código "ladeira abaixo" até chegar no dado sendo enviado ao pino do microcontrolador. Mas não deixa de ser uma ferramenta interessante...


 Um abração!

 Eduardo

-----
Olha só o arquivo LiquidCrystal.cpp (c plus plus)

Código:
#include "LiquidCrystal.h"

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"

// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set:
//    DL = 1; 8-bit interface data
//    N = 0; 1-line display
//    F = 0; 5x8 dot character font
// 3. Display on/off control:
//    D = 0; Display off
//    C = 0; Cursor off
//    B = 0; Blinking off
// 4. Entry mode set:
//    I/D = 1; Increment by 1
//    S = 0; No shift
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
}

LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

LiquidCrystal::LiquidCrystal(uint8_t rs,  uint8_t enable,
     uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
{
  init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
}

void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
{
  _rs_pin = rs;
  _rw_pin = rw;
  _enable_pin = enable;
 
  _data_pins[0] = d0;
  _data_pins[1] = d1;
  _data_pins[2] = d2;
  _data_pins[3] = d3;
  _data_pins[4] = d4;
  _data_pins[5] = d5;
  _data_pins[6] = d6;
  _data_pins[7] = d7;
 
 
  if (fourbitmode)
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
  else
    _displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;

#ifndef __ARDUINO_X86__
  begin(16, 1);
#endif 

}

void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
  if (lines > 1) {
    _displayfunction |= LCD_2LINE;
  }
  _numlines = lines;
  _currline = 0;

  // for some 1 line displays you can select a 10 pixel high font
  if ((dotsize != 0) && (lines == 1)) {
    _displayfunction |= LCD_5x10DOTS;
  }

  // Deferred initialized from init()
  pinMode(_rs_pin, OUTPUT);
  // we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
  if (_rw_pin != 255) {
    pinMode(_rw_pin, OUTPUT);
  }
  pinMode(_enable_pin, OUTPUT);
 
  // Do these once, instead of every time a character is drawn for speed reasons.
  for (int i=0; i<((_displayfunction & LCD_8BITMODE) ? 8 : 4); ++i)
    pinMode(_data_pins[i], OUTPUT);

  // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
  // according to datasheet, we need at least 40ms after power rises above 2.7V
  // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
  delayMicroseconds(50000);
  // Now we pull both RS and R/W low to begin commands
  digitalWrite(_rs_pin, LOW);
  digitalWrite(_enable_pin, LOW);
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }
 
  //put the LCD into 4 bit or 8 bit mode
  if (! (_displayfunction & LCD_8BITMODE)) {
    // this is according to the hitachi HD44780 datasheet
    // figure 24, pg 46

    // we start in 8bit mode, try to set 4 bit mode
    write4bits(0x03);
    delayMicroseconds(4500); // wait min 4.1ms

    // second try
    write4bits(0x03);
    delayMicroseconds(4500); // wait min 4.1ms
   
    // third go!
    write4bits(0x03);
    delayMicroseconds(150);

    // finally, set to 4-bit interface
    write4bits(0x02);
  } else {
    // this is according to the hitachi HD44780 datasheet
    // page 45 figure 23

    // Send function set command sequence
    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(4500);  // wait more than 4.1ms

    // second try
    command(LCD_FUNCTIONSET | _displayfunction);
    delayMicroseconds(150);

    // third go
    command(LCD_FUNCTIONSET | _displayfunction);
  }

  // finally, set # lines, font size, etc.
  command(LCD_FUNCTIONSET | _displayfunction); 

  // turn the display on with no cursor or blinking default
  _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; 
  display();

  // clear it off
  clear();

  // Initialize to default text direction (for romance languages)
  _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
  // set the entry mode
  command(LCD_ENTRYMODESET | _displaymode);

}

/********** high level commands, for the user! */
void LiquidCrystal::clear()
{
  command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystal::home()
{
  command(LCD_RETURNHOME);  // set cursor position to zero
  delayMicroseconds(2000);  // this command takes a long time!
}

void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
{
  int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
  if ( row >= _numlines ) {
    row = _numlines-1;    // we count rows starting w/0
  }
 
  command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void LiquidCrystal::noDisplay() {
  _displaycontrol &= ~LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::display() {
  _displaycontrol |= LCD_DISPLAYON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystal::noCursor() {
  _displaycontrol &= ~LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::cursor() {
  _displaycontrol |= LCD_CURSORON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystal::noBlink() {
  _displaycontrol &= ~LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal::blink() {
  _displaycontrol |= LCD_BLINKON;
  command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM
void LiquidCrystal::scrollDisplayLeft(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal::scrollDisplayRight(void) {
  command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void LiquidCrystal::leftToRight(void) {
  _displaymode |= LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystal::rightToLeft(void) {
  _displaymode &= ~LCD_ENTRYLEFT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystal::autoscroll(void) {
  _displaymode |= LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystal::noAutoscroll(void) {
  _displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
  command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystal::command(uint8_t value) {
  send(value, LOW);
}

inline size_t LiquidCrystal::write(uint8_t value) {
  send(value, HIGH);
  return 1; // assume sucess
}

/************ low level data pushing commands **********/

// write either command or data, with automatic 4/8-bit selection
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
  digitalWrite(_rs_pin, mode);

  // if there is a RW pin indicated, set it low to Write
  if (_rw_pin != 255) {
    digitalWrite(_rw_pin, LOW);
  }
 
  if (_displayfunction & LCD_8BITMODE) {
    write8bits(value);
  } else {
    write4bits(value>>4);
    write4bits(value);
  }
}

void LiquidCrystal::pulseEnable(void) {
  digitalWrite(_enable_pin, LOW);
#ifndef __ARDUINO_X86__
  delayMicroseconds(1);   
#endif 
  digitalWrite(_enable_pin, HIGH);
#ifndef __ARDUINO_X86__ 
  delayMicroseconds(1);    // enable pulse must be >450ns
#endif 
  digitalWrite(_enable_pin, LOW);
  delayMicroseconds(100);   // commands need > 37us to settle
}

void LiquidCrystal::write4bits(uint8_t value) {
  for (int i = 0; i < 4; i++) {
    digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }

  pulseEnable();
}

void LiquidCrystal::write8bits(uint8_t value) {
  for (int i = 0; i < 8; i++) {
digitalWrite(_data_pins[i], (value >> i) & 0x01);
  }
 
  pulseEnable();
}
« Última modificação: 05 de Março de 2015, as 19:26:48 por Ledod » Registrado
Ledod
Handmaker
****
Offline Offline

Sexo: Masculino
Mensagens: 1.132

Obrigado
-Dado: 17
-Recebido: 139



« Responder #12 : 08 de Março de 2015, as 11:47:14 »

 Um teste que fiz hoje com o STM32f100:

https://soundcloud.com/eduardo-mello-nottolini/guitar-pitch-shifter

 Basicamente utilizo um canal DMA do microcontrolador para mover os dados do ADC1 para um buffer de 1024 posições utilizando o timer1. A partir dai, utilizando um segundo canal do DMA, movo os dados para o DAC com um trigger vindo do timer2 em uma frequência diferente.

 Esses "plocs plocs" acontecem porque os dados estão crus, sem aplicar o "blend" quando um ponteiro passa pelo outro (há uma mudança de amplitude muito brusca).

 Mas é uma idéia inicial! Dá para melhorar!  Wink

 Abaixo o código main.c , utilizando o compilador IAR workbench. No fundo é "copy-paste" de dois exemplos já prontos e é só para referência mesmo! Está bem mal feito... Cheesy

 
Código:
/**
  ******************************************************************************
  * @file    DMA/ADC_TIM1/main.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"

/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup DMA_ADC_TIM1
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_Address         0x4001244C
#define TIM1_CCR1_Address       0x40012C34
#define DAC_DHR12RD_Address     0x40007420
#define DAC_DHR12R1             0x40007408

#define BUFFER_SIZE             1024
#define ADC_PERIOD_TIM          2000
#define DAC_PERIOD_TIM          1000

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ADC_InitTypeDef           ADC_InitStructure;
DAC_InitTypeDef            DAC_InitStructure;
TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
TIM_OCInitTypeDef         TIM_OCInitStructure;
DMA_InitTypeDef           DMA_InitStructure;
  
uint16_t mem_buffer[BUFFER_SIZE];
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
  
/* Private functions ---------------------------------------------------------*/

/**
  * @brief   Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
     */    
      
  /* System Clocks Configuration */
  RCC_Configuration();

  /* Configure the GPIO ports */
  GPIO_Configuration();

  /* DMA1 Channel5 configuration ----------------------------------------------*/
  DMA_DeInit(DMA1_Channel5);
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&mem_buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  /* Enable DMA1 Channel5 */
  DMA_Cmd(DMA1_Channel5, ENABLE);

  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 RegularChannelConfig Test */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);

  /* TIM1 configuration ------------------------------------------------------*/
  /* Time Base configuration */
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = ADC_PERIOD_TIM;
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  /* Enable TIM1 */  
  TIM_Cmd(TIM1, ENABLE);

  /* Enable TIM1 DMA interface */
  TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);

  /* Enable ADC1 reset calibration register */
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));

  /* Start ADC1 conversion */
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = DAC_PERIOD_TIM;          
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0;      
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* TIM2 TRGO selection */
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

  /* DAC channel1 Configuration */
  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
  DAC_Init(DAC_Channel_1, &DAC_InitStructure);

  /* DAC channel2 Configuration */
  DAC_Init(DAC_Channel_2, &DAC_InitStructure);


#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL
  /* DMA2 channel4 configuration */
  DMA_DeInit(DMA2_Channel4);
#else
  /* DMA1 channel4 configuration */
  DMA_DeInit(DMA1_Channel4);
#endif
  DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&mem_buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL
  DMA_Init(DMA2_Channel4, &DMA_InitStructure);
  /* Enable DMA2 Channel4 */
  DMA_Cmd(DMA2_Channel4, ENABLE);
#else
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);
  /* Enable DMA1 Channel4 */
  DMA_Cmd(DMA1_Channel4, ENABLE);
#endif

  /* Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is
     automatically connected to the DAC converter. */
  DAC_Cmd(DAC_Channel_1, ENABLE);
  /* Enable DAC Channel2: Once the DAC channel2 is enabled, PA.05 is
     automatically connected to the DAC converter. */
  DAC_Cmd(DAC_Channel_2, ENABLE);

  /* Enable DMA for DAC Channel2 */
  DAC_DMACmd(DAC_Channel_2, ENABLE);

  /* TIM2 enable counter */
  TIM_Cmd(TIM2, ENABLE);
  
  while (1)
  {
  }
}

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void RCC_Configuration(void)
{
  /* ADCCLK = PCLK2/8 */
  RCC_ADCCLKConfig(RCC_PCLK2_Div8);  

  /* Enable peripheral clocks ------------------------------------------------*/
  /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  /* Enable GPIOA, GPIOC, ADC1 and TIM1 Periph clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC |
                         RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE);
  
   /* Enable peripheral clocks ------------------------------------------------*/
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL
  /* DMA2 clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
#else
  /* DMA1 clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
#endif
  /* GPIOA Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  /* DAC Periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  /* TIM2 Periph clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval None
  */
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Configure TIM1 Channel1 output */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure ADC Channel14 as analog input */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4  ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}

#endif

/**
  * @}
  */

/**
  * @}
  */

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
« Última modificação: 08 de Março de 2015, as 12:02:12 por Ledod » Registrado
gfr
Colaborador
***
Offline Offline

Mensagens: 665

Obrigado
-Dado: 18
-Recebido: 86



« Responder #13 : 08 de Março de 2015, as 14:12:56 »

http://www.guitarpitchshifter.com/index.html

Bem didático, especialmente a seção 3 (algoritmo).
Registrado

Com o tempo, uma imprensa cínica, mercenária, demagógica e corrupta formará um público tão vil como ela mesma - Joseph Pulitzer
Páginas: [1]   Ir para o Topo
  Imprimir  
 
Ir para:  


Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines

XHTML 1.0 Válido! CSS Válido! Dilber MC Theme by HarzeM
Página criada em 0.051 segundos com 22 procedimentos.
SimplePortal 2.3.3 © 2008-2010, SimplePortal