Двойной LFO с выбором форм волны с использованием PT8211 и синей таблетки

Кенласли
Пт 24 ноября 2017 г. 14:12
Привет, ребята

Роджер призвал меня сделать пост здесь, так что вот я «Сделал решающий шаг». Мой первый код-шнур / проект.

От чтения примера кода Vasillis с использованием PT8211 (спасибо!), если подстегнуть меня к созданию двойного LFO.
Я был заинтересован в том, чтобы вытащить две независимые формы волны из чипа с выбором форм волн и частотой между 0.1 Гц и 100 Гц.

Код здесь, кажется, работает нормально. Есть, однако, проблема с генерируемыми сигналами. Особенно на более низких частотах.
/** Dual LFO for STM32F103C8T6 Description: This code generates separate low frequency waveforms on the two channels of the PT8211 DAC. My remit was for frequencies approximately between 0.1Hz and 100Hz (LFO) and a choice of waveforms including sine, saw, reverse saw, triangle and square Created by Ken Laszlo 24/11/2017 email: wight446-at-yahoo.com Thanks to Roger Clark, Vassilis Serasidis and Madis Connections between PT8211 DAC and the STM32F103C8T6 WS <--> PA3 BCK <--> PA5 <--> BOARD_SPI1_SCK_PIN DIN <--> PA7 <--> BOARD_SPI1_MOSI_PIN 100K Potentiometers on PA2 and PA4 providing a scaled voltage between 0 and 3.3v for frequency selection 100K Potentiometers on PA6 and PA8 providing a scaled voltage between 0 and 3.3v for wave type selection */ #include #define WS PA3 #define BCK PA5 #define DATA PA7 #define SINE 0 #define SAWTOOTH 1 #define REVSAWTOOTH 2 #define TRIANGLE 3 #define SQUARE 4 int waveRead; byte waveType1 = SINE; byte waveType2 = SAWTOOTH; int maxSamples1 = 512; int maxSamples2 = 512; int sampPos1, sampPos2 = 0; int ratio1, ratio2; int phaseAccumulator1, phaseAccumulator2 = 0; uint16_t thisSample1, thisSample2; // 16 Bit as these will be fed to the DAC // Sine generator // http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml // Triangle generator // http://www.daycounter.com/Calculators/Triangle-Wave-Generator-Calculator.phtml // A 512 point Sine Array (-32767 to +32767) const uint16_t sineArray[512] PROGMEM = { 1, 403, 805, 1207, 1608, 2010, 2411, 2812, 3212, 3612, 4012, 4410, 4808, 5206, 5602, 5998, 6393, 6787, 7180, 7572, 7962, 8352, 8740, 9127, 9512, 9896, 10279, 10660, 11040, 11417, 11793, 12168, 12540, 12911, 13279, 13646, 14010, 14373, 14733, 15091, 15447, 15800, 16152, 16500, 16846, 17190, 17531, 17869, 18205, 18538, 18868, 19196, 19520, 19842, 20160, 20476, 20788, 21097, 21403, 21706, 22006, 22302, 22595, 22885, 23171, 23453, 23732, 24008, 24280, 24548, 24812, 25073, 25330, 25583, 25833, 26078, 26320, 26557, 26791, 27020, 27246, 27467, 27684, 27897, 28106, 28311, 28511, 28707, 28899, 29086, 29269, 29448, 29622, 29792, 29957, 30118, 30274, 30425, 30572, 30715, 30853, 30986, 31114, 31238, 31357, 31471, 31581, 31686, 31786, 31881, 31972, 32058, 32138, 32214, 32286, 32352, 32413, 32470, 32522, 32568, 32610, 32647, 32679, 32706, 32729, 32746, 32758, 32766, 32767, 32766, 32758, 32746, 32729, 32706, 32679, 32647, 32610, 32568, 32522, 32470, 32413, 32352, 32286, 32214, 32138, 32058, 31972, 31881, 31786, 31686, 31581, 31471, 31357, 31238, 31114, 30986, 30853, 30715, 30572, 30425, 30274, 30118, 29957, 29792, 29622, 29448, 29269, 29086, 28899, 28707, 28511, 28311, 28106, 27897, 27684, 27467, 27246, 27020, 26791, 26557, 26320, 26078, 25833, 25583, 25330, 25073, 24812, 24548, 24280, 24008, 23732, 23453, 23171, 22885, 22595, 22302, 22006, 21706, 21403, 21097, 20788, 20476, 20160, 19842, 19520, 19196, 18868, 18538, 18205, 17869, 17531, 17190, 16846, 16500, 16152, 15800, 15447, 15091, 14733, 14373, 14010, 13646, 13279, 12911, 12540, 12168, 11793, 11417, 11040, 10660, 10279, 9896, 9512, 9127, 8740, 8352, 7962, 7572, 7180, 6787, 6393, 5998, 5602, 5206, 4808, 4410, 4012, 3612, 3212, 2812, 2411, 2010, 1608, 1207, 805, 403, 1, -402, -804, -1206, -1607, -2009, -2410, -2811, -3211, -3611, -4011, -4409, -4807, -5205, -5601, -5997, -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126, -9511, -9895, -10278, -10659, -11039, -11416, -11792, -12167, -12539, -12910, -13278, -13645, -14009, -14372, -14732, -15090, -15446, -15799, -16151, -16499, -16845, -17189, -17530, -17868, -18204, -18537, -18867, -19195, -19519, -19841, -20159, -20475, -20787, -21096, -21402, -21705, -22005, -22301, -22594, -22884, -23170, -23452, -23731, -24007, -24279, -24547, -24811, -25072, -25329, -25582, -25832, -26077, -26319, -26556, -26790, -27019, -27245, -27466, -27683, -27896, -28105, -28310, -28510, -28706, -28898, -29085, -29268, -29447, -29621, -29791, -29956, -30117, -30273, -30424, -30571, -30714, -30852, -30985, -31113, -31237, -31356, -31470, -31580, -31685, -31785, -31880, -31971, -32057, -32137, -32213, -32285, -32351, -32412, -32469, -32521, -32567, -32609, -32646, -32678, -32705, -32728, -32745, -32757, -32765, -32767, -32765, -32757, -32745, -32728, -32705, -32678, -32646, -32609, -32567, -32521, -32469, -32412, -32351, -32285, -32213, -32137, -32057, -31971, -31880, -31785, -31685, -31580, -31470, -31356, -31237, -31113, -30985, -30852, -30714, -30571, -30424, -30273, -30117, -29956, -29791, -29621, -29447, -29268, -29085, -28898, -28706, -28510, -28310, -28105, -27896, -27683, -27466, -27245, -27019, -26790, -26556, -26319, -26077, -25832, -25582, -25329, -25072, -24811, -24547, -24279, -24007, -23731, -23452, -23170, -22884, -22594, -22301, -22005, -21705, -21402, -21096, -20787, -20475, -20159, -19841, -19519, -19195, -18867, -18537, -18204, -17868, -17530, -17189, -16845, -16499, -16151, -15799, -15446, -15090, -14732, -14372, -14009, -13645, -13278, -12910, -12539, -12167, -11792, -11416, -11039, -10659, -10278, -9895, -9511, -9126, -8739, -8351, -7961, -7571, -7179, -6786, -6392, -5997, -5601, -5205, -4807, -4409, -4011, -3611, -3211, -2811, -2410, -2009, -1607, -1206, -804, -402, }; // A 512 point Triangle Array (-32767 to +32767) const uint16_t triangleArray[512] PROGMEM = { -32511, -32255, -31999, -31743, -31487, -31231, -30975, -30719, -30463, -30207, -29951, -29695, -29439, -29183, -28927, -28671, -28415, -28159, -27903, -27647, -27391, -27135, -26879, -26623, -26367, -26111, -25855, -25599, -25343, -25087, -24831, -24575, -24319, -24063, -23807, -23551, -23295, -23039, -22783, -22527, -22271, -22015, -21759, -21503, -21247, -20991, -20735, -20479, -20223, -19967, -19711, -19455, -19199, -18943, -18687, -18431, -18175, -17919, -17663, -17407, -17151, -16895, -16639, -16383, -16127, -15871, -15615, -15359, -15103, -14847, -14591, -14335, -14079, -13823, -13567, -13311, -13055, -12799, -12543, -12287, -12031, -11775, -11519, -11263, -11007, -10751, -10495, -10239, -9983, -9727, -9471, -9215, -8959, -8703, -8447, -8191, -7935, -7679, -7423, -7167, -6911, -6655, -6399, -6143, -5887, -5631, -5375, -5119, -4863, -4607, -4351, -4095, -3839, -3583, -3327, -3071, -2815, -2559, -2303, -2047, -1791, -1535, -1279, -1023, -767, -511, -255, 1, 256, 512, 768, 1024, 1280, 1536, 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, 5888, 6144, 6400, 6656, 6912, 7168, 7424, 7680, 7936, 8192, 8448, 8704, 8960, 9216, 9472, 9728, 9984, 10240, 10496, 10752, 11008, 11264, 11520, 11776, 12032, 12288, 12544, 12800, 13056, 13312, 13568, 13824, 14080, 14336, 14592, 14848, 15104, 15360, 15616, 15872, 16128, 16384, 16640, 16896, 17152, 17408, 17664, 17920, 18176, 18432, 18688, 18944, 19200, 19456, 19712, 19968, 20224, 20480, 20736, 20992, 21248, 21504, 21760, 22016, 22272, 22528, 22784, 23040, 23296, 23552, 23808, 24064, 24320, 24576, 24832, 25088, 25344, 25600, 25856, 26112, 26368, 26624, 26880, 27136, 27392, 27648, 27904, 28160, 28416, 28672, 28928, 29184, 29440, 29696, 29952, 30208, 30464, 30720, 30976, 31232, 31488, 31744, 32000, 32256, 32512, 32767, 32512, 32256, 32000, 31744, 31488, 31232, 30976, 30720, 30464, 30208, 29952, 29696, 29440, 29184, 28928, 28672, 28416, 28160, 27904, 27648, 27392, 27136, 26880, 26624, 26368, 26112, 25856, 25600, 25344, 25088, 24832, 24576, 24320, 24064, 23808, 23552, 23296, 23040, 22784, 22528, 22272, 22016, 21760, 21504, 21248, 20992, 20736, 20480, 20224, 19968, 19712, 19456, 19200, 18944, 18688, 18432, 18176, 17920, 17664, 17408, 17152, 16896, 16640, 16384, 16128, 15872, 15616, 15360, 15104, 14848, 14592, 14336, 14080, 13824, 13568, 13312, 13056, 12800, 12544, 12288, 12032, 11776, 11520, 11264, 11008, 10752, 10496, 10240, 9984, 9728, 9472, 9216, 8960, 8704, 8448, 8192, 7936, 7680, 7424, 7168, 6912, 6656, 6400, 6144, 5888, 5632, 5376, 5120, 4864, 4608, 4352, 4096, 3840, 3584, 3328, 3072, 2816, 2560, 2304, 2048, 1792, 1536, 1280, 1024, 768, 512, 256, 1, -255, -511, -767, -1023, -1279, -1535, -1791, -2047, -2303, -2559, -2815, -3071, -3327, -3583, -3839, -4095, -4351, -4607, -4863, -5119, -5375, -5631, -5887, -6143, -6399, -6655, -6911, -7167, -7423, -7679, -7935, -8191, -8447, -8703, -8959, -9215, -9471, -9727, -9983, -10239, -10495, -10751, -11007, -11263, -11519, -11775, -12031, -12287, -12543, -12799, -13055, -13311, -13567, -13823, -14079, -14335, -14591, -14847, -15103, -15359, -15615, -15871, -16127, -16383, -16639, -16895, -17151, -17407, -17663, -17919, -18175, -18431, -18687, -18943, -19199, -19455, -19711, -19967, -20223, -20479, -20735, -20991, -21247, -21503, -21759, -22015, -22271, -22527, -22783, -23039, -23295, -23551, -23807, -24063, -24319, -24575, -24831, -25087, -25343, -25599, -25855, -26111, -26367, -26623, -26879, -27135, -27391, -27647, -27903, -28159, -28415, -28671, -28927, -29183, -29439, -29695, -29951, -30207, -30463, -30719, -30975, -31231, -31487, -31743, -31999, -32255, -32511, -32767, }; HardwareTimer timer(3); void setup() { pinMode(PA2, INPUT_ANALOG); // LFO Rate Potentiometers pinMode(PA4, INPUT_ANALOG); pinMode(PA6, INPUT_ANALOG); // Wavetype Potentiometers - We can calculate 'voltage represents wavetype' for our needs pinMode(PA8, INPUT_ANALOG); // A3, A5 and A7 are in use by the PT8211 DAC SPI.begin(); // Initialize the SPI_1 port. SPI.setBitOrder(MSBFIRST); // Set the SPI_1 bit order SPI.setDataMode(SPI_MODE0); // Set the SPI_2 data mode 0 SPI.setClockDivider(SPI_CLOCK_DIV4); // Speed (72 / 4 = 18 MHz SPI_1 speed) PT8211 up to 20MHZ clock pinMode(WS, OUTPUT); // Set the Word Select pin (WS) as output. SPI.setDataSize (SPI_CR1_DFF); // Set SPI data size to 16Bit // timer3 setup timer.pause(); // Pause the timer while we're configuring it timer.setPeriod(20); // Set up period in microseconds -- 40 Microseconds gives 100Hz with 256 samples per second, 20 Microseconds give 100Hz with 512 samps/s timer.setChannel1Mode(TIMER_OUTPUT_COMPARE); // Set up an interrupt on channel 1 timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update timer.attachCompare1Interrupt(update_sample); // The interrupt routine we shall run timer.refresh(); // Refresh the timer's count, prescale, and overflow timer.resume(); // Start the timer counting } void loop () { maxSamples1 = 512 + (analogRead(PA2) * 16 ); maxSamples2 = 512 + (analogRead(PA4) * 16 ); waveRead = analogRead(PA6); // 12 bits - 0 to 4095 switch (waveRead) { // Set the wavetype1 from the value received case 0000 ... 800: waveType1 = SINE; break; case 801 ... 1600: waveType1 = SAWTOOTH; break; case 1601 ... 2400: waveType1 = REVSAWTOOTH; break; case 2401 ... 3200: waveType1 = TRIANGLE; break; case 3201 ... 4095: waveType1 = SQUARE; break; } waveRead = analogRead(PA8); // 12 bits - 0 to 4095 switch (waveRead) { // Set the wavetype2 from the value received case 0000 ... 800: waveType2 = SINE; break; case 801 ... 1600: waveType2 = SAWTOOTH; break; case 1601 ... 2400: waveType2 = REVSAWTOOTH; break; case 2401 ... 3200: waveType2 = TRIANGLE; break; case 3201 ... 4095: waveType2 = SQUARE; break; } } void update_sample(void) { phaseAccumulator1++; // Move to next samples position phaseAccumulator2++; if (phaseAccumulator1 >= maxSamples1) phaseAccumulator1 = 0; // Check for overflow i.e. value of 1024 at max freq if (phaseAccumulator2 >= maxSamples2) phaseAccumulator2 = 0; ratio1 = maxSamples1 * 10000; ratio2 = maxSamples2 * 10000; ratio1 = ratio1 / 512; // (Bit shift 10 right is no faster / the same) ratio2 = ratio2 / 512; sampPos1 = phaseAccumulator1 * 10000; sampPos2 = phaseAccumulator2 * 10000; sampPos1 = sampPos1 / ratio1; sampPos2 = sampPos2 / ratio2; switch (waveType1) { case SINE: thisSample1 = pgm_read_word_near(&sineArray[(int)sampPos1]); break; case SAWTOOTH: thisSample1 = ((sampPos1 - 255) * 128); break; case REVSAWTOOTH: thisSample1 = ((255 - sampPos1) * 128); break; case TRIANGLE: thisSample1 = pgm_read_word_near(&triangleArray[(int)sampPos1]); break; case SQUARE: if (sampPos1 < 256) { thisSample1 = 32767; } else { thisSample1 = -32767; } break; } switch (waveType2) { case SINE: thisSample2 = pgm_read_word_near(&sineArray[(int)sampPos2]); break; case SAWTOOTH: thisSample2 = ((sampPos2 - 255) * 128); break; case REVSAWTOOTH: thisSample2 = ((255 - sampPos2) * 128); break; case TRIANGLE: thisSample2 = pgm_read_word_near(&triangleArray[(int)sampPos2]); break; case SQUARE: if (sampPos2 < 256) { thisSample2 = 32767; } else { thisSample2 = -32767; } break; } // Write the values to the DAC gpio_write_bit(GPIOA, 3, LOW); // Replaces digitalWrite(WS, LOW); Select RIGHT Audio channel SPI.write(thisSample1); gpio_write_bit(GPIOA, 3, HIGH); // Replaces digitalWrite(WS, HIGH); Select LEFT Audio channel SPI.write(thisSample2); }

Кенласли
Пт 24 ноября 2017 г. 14:13
Revsaw.jpg
Revsaw.JPG (39.43 киб) просмотрено 899 раз

Zoomx
Пт 24 ноября 2017 г. 15:26
Интересный!
Я нашел только одну доску с Pt8211, той Пол Стоффреген. Это дешево, менее 3 $, но, к сожалению, стоимость доставки в Европу составляет от 13 до 16 долларов в зависимости от веса.

Кенласли
Пт 24 ноября 2017 г. 16:31
Мне удалось получить десять чипов SMD PT8211 от eBay (отправлено из Китая) за 1.88 долларов США.
Я получил четыре платы SMD до Adapter Adapter Adapter от продавца Великобритании за 1.89 UKP.
Грязь дешево.

Кен

Ахулл
Пт 24 ноября 2017 г., 17:03
Эти квадратные волны выглядят так, как будто они проходят через какой -то фильтр L/C или R/C, вы уверены, что проблема не с вашим объемом или зондами. Попробуйте прицел на DC связан, а не AC связан, так как частота такая низкая. Если это не имеет значения, попробуйте пару коротких проводов вместо зонда.

РЕДАКТИРОВАТЬ: ОК, мне нужно научиться читать пост * целый * в будущем...
Выход PT8211 проходит через конденсатор 47 UF к потенциальному разделителю двух резисторов, чтобы снизить уровень до 1 В пик до пика, прежде чем отправить его в линию на ПК. Я подозреваю, что это ваша проблема, что комбинация конденсаторов/резисторов будет действовать как фильтр R/C и будет иметь негативное влияние, что станет более выраженным, чем меньше частота... Попробуйте заменить конденсатор 47UF подходящим резистором.. Не зная значений вашего делителя напряжения, я предлагаю вам попробовать горшок с 10 или 47 тыс., Начните с полного сопротивления и настраивайте его, пока не получите подходящую амплитуду для ваших целей, а затем замените резистором этого значения (если вы не хотите делать Математика для расчета требуемого значения).

Дэйв Дж
Пт 24 ноября 2017 г., 17:12
[Кенласли - Пт 24 ноября 2017 г. 14:12] - Выход PT8211 проходит через конденсатор 47 UF к потенциальному разделителю двух резисторов, чтобы снизить уровень до 1 В пик до пика, прежде чем отправить его в линию на ПК. Захваты экрана взяты из программного программного осциллографа ПК, используя линию звуковой карты при входе.
Входы звуковой карты почти всегда связаны с AC, поэтому не обрабатывают очень низкие частоты или устойчивые напряжения. Без надлежащего прицела захват набора образцов с помощью микроконтроллера с АЦП, передачи их на ПК и отображение их в приложении для графики (даже электронная таблица) - самый простой способ получить графики формы сигнала.

Ахулл
Пт 24 ноября 2017 г., 17:14
.. или вы могли бы Построить свинья и используйте это, чтобы измерить формы волны : D У него нет фильтрации или буферизации вообще.

Пито
Пт 24 ноября 2017 г. 18:29
RC называется «интегративная цепь (низкая частота)», RC, как CR, называется «производная цепь (высокая частота)».

Когда вы интегрируете или дифференцируете сигнал синусоидации/косинуса, вы получите одинаковую форму сигнала (математика).

С входным сигналом, как показано ниже RC, будет «округлить края», в то время как CR лучше пропускает быстрые изменения (ребра) и подавит медленные меняющиеся части сигнала.

Передача сигнала CR вытягивается - симметрично вокруг нулевого уровня - также.
Это потому, что CR подавляет постоянную часть сигнала - DC делает «недостаточно быстро меняется :) проходить через CR », в приведенном ниже примере dc = 2.5 В. Мы также говорим, что Cr "разместит" часть DC сигнала.

Поэтому ваш сигнал будет читать -1.От 25 до 1.25vpp на выходе растителя R1/R2 Наконец -то (см. Ниже).
Rc_dervation.jpg
Rc_dervation.JPG (64.51 киб) просмотрено 855 раз

Кенласли
Солнце 26 ноября 2017 г., 19:06
Спасибо всем за вашу помощь и дальнейший вклад.
Эти маленькие Pt8211s гениальны!
[Ахулл - Пт 24 ноября 2017 г., 17:03] - Я подозреваю, что это ваша проблема, эта комбинация конденсаторов/резисторов будет действовать как фильтр R/C и будет иметь негативное влияние
[Пито - Пт 24 ноября 2017 г. 18:29] - С входным сигналом, как показано ниже RC, будет «округлить края», в то время как CR лучше пропускает быстрые изменения (ребра) и подавит медленные меняющиеся части сигнала.
Привет, пито - хорошие схемы, вывод и объяснения! Прохладный!

Спасибо, глава - я понимаю. Немного ошибки в школьном мальчике на самом деле.
Я уверен, что схема и код работают правильно. Мне нужно прочитать выход на устройстве DC, связанного с DC.
[Ахулл - Пт 24 ноября 2017 г., 17:14] - .. Или вы можете построить свиньи и использовать его для измерения форм волны : D У него нет фильтрации или буферизации вообще.
Ух ты! Спасибо за указатель - я только что заказал один из 2.4 -дюймовые дисплеи примерно для 4 UKP и еще одну синюю таблетку.
Еще один будущий проект!

Кен

Rogerclark
Солнце 26 ноября 2017 г. 9:02 вечера
Кен

Отличный пост..

Повторите ваш код.

Ты не ДОН’T нужно использовать ProgMem или функцию для его чтения, пространство памяти плоское

Просто определите свои массивы как const, достаточно, чтобы положить их в вспышку ..

Аналоговое чтение является медленной для совместимости с AVR, который имеет выделенные аналоговые выводы и, следовательно, не нужно устанавливать режим PIN

STM32Is отличается, так как булавки имеют многочисленное использование, поэтому, если я помню правильные, аналогичные вызовы PinMode

На внутреннем API Libmaple есть прямой вызов, чтобы прочитать аналоговый ввод, но вам нужно будет посмотреть в ядре как можно’не помни с макушки моей головы, что это’S называется. Вам также понадобится вызов Pinmode в настройке

Я думаю, что в нескольких местах есть потенциально улучшения скорости, где можно объединить расчеты на 2 линии, но я печатаю этот пост на своем iPad, и это’СДЕЛАЕТ ТРУДНЫ

Rogerclark
Солнце 26 ноября 2017 г. 11:22
Я не уверен, что это очень ускорит, но phaseAccumulator1++; // Move to next samples position phaseAccumulator2++; if (phaseAccumulator1 >= maxSamples1) phaseAccumulator1 = 0; // Check for overflow i.e. value of 1024 at max freq if (phaseAccumulator2 >= maxSamples2) phaseAccumulator2 = 0;

Кенласли
Пн 27 ноября 2017 г. 10:24
Привет, Роджер

Спасибо за дополнения - да, я понимаю.
Я прихожу из фона AVR, поэтому не полностью знаком с тем, как работают эти новые 32 -битные устройства.

Случайно, я заметил, что захват 16-битной выборки из волны в флэш-памяти (например, синус) было на дробь медленнее, чем выполнение одной или двух 32-разрядных математических функций, чтобы сгенерировать форму волны (как в пиле и обратной пище)-это был удивительным. В нем было только увеличение скорости (например, с 440 Гц до 450 Гц на свободном генераторе в основной петле, не с использованием прерываний), но скорость не увеличивается, тем не менее.
В разделе для расчета форм волн было аналогичное изменение увеличения «переключателя/корпуса» на «if/thens/else» для расчета форм волн.

Кен

Rogerclark
Пн 27 ноября 2017 г., 19:29
Доступ к Flash не находится на полной тактовой скорости процессора. Я думаю, есть либо 2 или 1 “ожидание состояний” Для каждого чтения.

Попробуйте снять материал Progmem и удалить объявление Const на одном из волновых таблиц, и он должен быть помещен в оперативную память, что будет намного быстрее

Кенласли
Вт 28 ноября 2017 г. 11:23
Спасибо, да. Я могу подтвердить, что вытащить таблицу из флеш. Не резко, но определенное увеличение.
В прошедшей петле время, сокращенное с 3.20 микросекунд до 3.14 микросекунд.

Недавно я экспериментировал с разгоном чипа на 128 МГц и изменил (spi_clock_div4) на (spi_clock_div8), чтобы гарантировать, что PT8211 работал в пределах . . . И все сработало нормально.
Проверка цикла частоты, генерирующая частоту, увеличилась с 630 Гц до более 1.1 кГц только этим разгоном.
Я волновался, что могут быть ошибки, читая горшки с этой негарантированной скоростью (ADC), но они также казались в порядке.

Я почти уверен, что главный временной хог (возможно, неизбежный) взят SPI.Записать команду, которая, по моим расчетам, принимает 1.3 микросекунда только для завершения.

Я смотрю на то, чтобы получить как можно больше скорости, как только могу, для одной из моих будущих целей будет использовать чип для полного диапазона аудиочастот с несколькими выборами формы сигнала . . . Прямо сейчас это выглядит довольно высокий заказ.

Кен

Стивестронг
Вт 28 ноября 2017 г. 13:02
SPI.Команда записи будет длиться. время, необходимое для передачи битов данных с частотой SPI.
Поэтому, если вы установите частоту SPI на 36 МГц, то написание одного байта должен занять ~ 0,3 мксет.
Более низкая частота тактовой частоты SPI будет соответствующим образом увеличить время.

Кенласли
Вт 28 ноября 2017 г. 13:40
Спасибо, Стив.

PT8211 имеет максимальную номинальную тактовую частоту 20 МГц . . .. однако . . . Мое мышление было таким же, как и у вас ;) .
Я изменил дивизию тактовой частоты на 72 /2 (36 МГц), и он все еще работает нормально.
Похоже, Pt8211 (ну, по крайней мере, мой чип) может быть переоценен.
Дальнейшее тестирование для стабильности.

Кен

Rogerclark
Вт 28 ноября 2017 г., 8:49 вечера
Вызов SpiWrite для одиночных байтов не очень эффективен, есть много накладных расходов, если SPI готов принять данные

Вы можете попробовать обйти эти чеки и просто прямо написать в реестр вывода SPI

victor_pv
Вт 28 ноября 2017 г. 22:40
Если вы хотите ускорить ситуацию, вы должны посмотреть на использование DMA.
Затем процессор может что -то сделать, например, процесс или заполнение буфера, в то время как DMA отправляет другой сам по себе на периферийное устройство SPI.
Таким образом, процессор не должен сидеть на холостом ходу, ожидая передачи SPI.

Некоторые из этих MCU имеют режим I2S, и в этом режиме периферийная пластинка SPI может генерировать сигнал WS самостоятельно. Это не так на чертеже, но вы должны иметь возможность использовать таймер для достижения того же.
Настройте таймер для переполнения на нужную вам частоту. Установите выходной выход канала для переворачивания на CC Match и установите значение на половину переполнения таймера, так что будет 1 матч даже на переполнение таймера.
Затем настройте канал DMA, к которому подключен этот канал таймера (проверьте справочное руководство), чтобы выполнить запросы DMA для периферийного устройства SPI. Включите запросы DMA в канале таймера (не периферийное устройство SPI, поскольку, когда для выполнения передачи будут решаться таймером, а не периферийным устройством SPI).
Затем построите свой стол с образцами в оперативной памяти и запустите таймер.
Каждый раз, когда таймер CC соответствует количеству таймера, выход WS (выход канала таймера) будет переключаться на противоположное значение (0 PR 1), а будет сгенерирован новый запрос DMA/ периферийное устройство DMA будет загружать образец из ОЗУ, нагрузки это в Spi DR Register, и SPI отправит его.
На следующем CC Match вывод WS снова переключится, для другого канала, а DMA выберет новый образец и загрузит его в DR, который отправит его.

Если у меня будет время, я попробую написать вам код позже.

Rogerclark
Вторник 28 ноября 2017 г. 11:24
Виктор.

У меня была такая же мысль

Просто настройте DMA с помощью волнового буфера и настройте таймер, чтобы генерировать прерывания, чтобы вызвать DMA на соответствующей скорости.

Но я не был уверен, было ли это возможно или как это настроить.

Кенласли
Ср 29 ноября 2017 г., 23:20
Спасибо.

Я просто взломал SPI.ч сейчас.

spi_tx_reg (_currentsetting->spi_d, data); // Записать данные, которые будут переданы в регистр SPI_DR (это очищает флаг TXE)

Я с интересом смотрю на SPI.dmasend и твой SPI.dmasendasync что вы разработали для использования с неопикселями.
Понадобится ли мне особое внимание, чтобы использовать эти команды, пожалуйста?
Даже использование не блокирующего DMA Send для одного 16 -битного данных было бы полезно для меня.
Pehaps Эти команды могут быть лучшим вариантом, так как я предполагаю проблемы с временем с написанием непосредственно в реестр и не проверяю, если данные закончат отправлены или что SPI готов снова, прежде чем снова зайти для другой отправки.

На данный момент мой код работает на основе образца, причем каждый образец рассчитывается по состоянию разных вещей . . . Отправка большого блока «предопределенных» образцов, которые должны быть переданы с использованием DMA, может быть невозможна для моего проекта в его текущей форме.

Кен

Rogerclark
Ср 29 ноября 2017 г. 11:28
Я предполагаю, что вам нужно будет контролировать скорость, с которой DMA отправляет волновую стола, в противном случае у вас не будет управления частотой формы выходной сигнала, так как он будет просто быстро, как DMA может выдвинуть его к шине SPI, я.E 36 МГц, если хотите...

Кенласли
Ср 29 ноября 2017 г. 11:49
Ну, кажется, это вещь :)

Мой подход заключался в том, что частота контролировалась переменной фазовой аккумулятора, а не установленной частотой, в которой данные отправляются через DMA.
Таким образом (в простых терминах) установлена ​​скорость отправки данных, но количество отправленных образцов изменяется.
На самом деле, я сделал именно это. Я написал какой -то код для VCO (DCO), работающего с несколькими сигналами, выводится до 12 кГц и полностью управляемо. Проблема такова . . . ужасный псевдоним для чего -либо выше 1.2 кГц, вызванная неспособностью работать с высокой скоростью дискретизации.

Кен

Rogerclark
Чт 30 ноября 2017 г. 12:24
Я не смотрел на ваш код, но вы интерполируете значения ? Для получения дополнительных данных ?

Я не эксперт в этом, но я предполагаю, чтобы получить наилучшее разрешение на результаты, вам всегда нужно работать с максимальной скоростью дискретизации и соответственно построить буфер DMA, e.глин. Интерполируя промежуточное значение между теми, которые в ваших волнообразных

Однако в зависимости от вашего алгоритма интерполяции и сколько баллов вам нужно для создания, скорость процессора будет ограничением.

STM32 Duino *Loop *

Обратно