Título: Pitch Shitfter DIY
Enviado por: Tiago Vulgar em 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 (https://www.youtube.com/watch?v=_KwS2qCCGzs). É um Pitch Shifter, só que o cara usa em um MP3 Player. Pois bem, no vídeo tem um link que é deste fórum (http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=2003) onde o cara postou algumas fotos e detalhes do projeto, também no mesmo fórum eu encontrei o link (http://elm-chan.org/works/vp/report.html) 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:
(http://dangerousprototypes.com/forum/download/file.php?id=5903&mode=view)
Título: Re: Pitch Shitfter DIY
Enviado por: marcao_cfh em 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...
Título: Re: Pitch Shitfter DIY
Enviado por: Ledod em 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á! :D
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
Título: Re: Pitch Shitfter DIY
Enviado por: xformer em 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.
Título: Re: Pitch Shitfter DIY
Enviado por: Tiago Vulgar em 04 de Março de 2015, as 19:58:11
Ledod, meu conhecimento sobre PIC tende a zero :-[ , 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 (https://www.youtube.com/watch?v=Xe-Vy3HDyQ4) 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. :-X
Título: Re: Pitch Shitfter DIY
Enviado por: xformer em 04 de Março de 2015, as 21:22:15
Ledod, meu conhecimento sobre PIC tende a zero :-[ , 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. :-X
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.
Título: Re: Pitch Shitfter DIY
Enviado por: Ledod em 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:
(http://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/Major_scale_in_the_chromatic_circle.png/220px-Major_scale_in_the_chromatic_circle.png)
Título: Re: Pitch Shitfter DIY
Enviado por: hgamal em 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!
Título: Re: Pitch Shitfter DIY
Enviado por: kem em 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?
Título: Re: Pitch Shitfter DIY
Enviado por: Tiago Vulgar em 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)!
Título: Re: Pitch Shitfter DIY
Enviado por: xformer em 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.
Título: Re: Pitch Shitfter DIY
Enviado por: Ledod em 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) #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(); }
Título: Re: Pitch Shitfter DIY
Enviado por: Ledod em 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! ;) 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... :D /** ****************************************************************************** * @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>© 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****/
Título: Re: Pitch Shitfter DIY
Enviado por: gfr em 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).
|