Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: I2S Slave Прием - хелп!
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Allregia
Работал с I2S-мастером, что прием что передача в 16 битах - никаких проблем небыло.
Сейчас пробую прием слейвом 24-2 бита, не могу понять где глюки.

I2S3 - мастер-передатчик, с него подаю прямо на I2S2 - слейв-приемник.
Передаю одно и то-же число в каждом канале, 32 бита, 48кгц., передатик тактируется внешним клоком.
Контролирую осциллографом шину - там все идеально, числа соответствуют.
Приемник считывает в 2 переменые - и там числа не совпадают с переданными.
Причем клик на ресет - и там уже другие числа.

Инициализация приемника такая:
CODE

void InitI2S2(void){ // slave receiver

I2S_InitTypeDef I2S2_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
u32 d;

RCC_I2SCLKConfig(RCC_I2S2CLKSource_Ext);
/* Enable the I2S peripheral clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

// GPIO
GPIO_PinAFConfig(GPIOB,GPIO_PinSource12, GPIO_AF_SPI2); // WCLK
GPIO_PinAFConfig(GPIOB,GPIO_PinSource13, GPIO_AF_SPI2); // BCLK
GPIO_PinAFConfig(GPIOB,GPIO_PinSource15, GPIO_AF_SPI2); // SDATA

GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15; // WCLK, BCLK, SDATA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOB, &GPIO_InitStructure);

//------------------------------------------------------------------------
I2S_StructInit(&I2S2_InitStructure);
I2S2_InitStructure.I2S_AudioFreq =I2S_AudioFreq_Default;
I2S2_InitStructure.I2S_Standard = I2S_Standard_MSB;
I2S2_InitStructure.I2S_DataFormat = I2S_DataFormat_32b;
I2S2_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S2_InitStructure.I2S_Mode = I2S_Mode_SlaveRx;
I2S2_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;

I2S_Init(SPI2, &I2S2_InitStructure);
// -------------- interrupt:
NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2SInputPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = I2SInputSubPriority;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

while( (GPIOB->IDR & GPIO_Pin_12) 0= 0 ); // wait for WCLK=1
while( (GPIOB->IDR & GPIO_Pin_12) != 0 );// wait for WCLK=0

d=(uint32_t)SPI3->DR; // to clear RXNE bit if was
d=(uint32_t)SPI3->SR; // to clear flags, if were

SPI_I2S_ITConfig(SPI2,SPI_I2S_IT_RXNE,ENABLE); // enable interrupt

I2S_Cmd(SPI2, ENABLE); // enable I2S2
}


прием по прерыванию делаю так:
Код
volatile u16 LDataRcvL, LDataRcvH, RDataRcvL, RDataRcvH; // сюда считываю
    
void SPI2_IRQHandler(void){
     static u32 chan, sequence;
    
        chan = (SPI2->SR & I2S_FLAG_CHSIDE);               // read CHSIDE = 0 for LEFT, 1 for RIGHT
        InpData=SPI2->DR;//SPI_I2S_ReceiveData(SPI2);   //  read reveived data
        sequence <<= 1;              // bit1 = old
        sequence &= 0x2;             // leave only bit1 = old chan value
        if (chan)  sequence |=1;   //  bit0 = new chan value
        //---------------------------------------------------------
        switch (sequence){
             case 0:  LDataRcvL = InpData; break;    // Left Low
             case 2:  LDataRcvH = InpData; break;    // Left High
             case 1:  RDataRcvH = InpData; break;   //  Right High
             case 3:  RDataRcvL = InpData; break;   //  Right Low,  End Of 2 channel receiving
       }
  }


Помогите пожалуйста, понять в чем дело. Второй день бьюсь, что я делаю не так?
Чувствую что где-то какая-то детская ошибка, понять бы где...
drum1987
в прерывании sequence изначально чему равно?
если 0 как "по умолчанию", то строки:
sequence <<= 1; // bit1 = old
sequence &= 0x2; // leave only bit1 = old chan value
делают непонять че...
если не нулю, а случайным числам, то тоже все понятно.
Allregia
Цитата(drum1987 @ Mar 4 2013, 19:14) *
в прерывании sequence изначально чему равно?


При старте программы - нулю, разумеется.

Цитата
если 0 как "по умолчанию", то строки:
sequence <<= 1; // bit1 = old
sequence &= 0x2; // leave only bit1 = old chan value
делают непонять че...


0-й бит, который был равен chan в прошлый раз, сдвигается и становиться bit1 = old value. Все остальные биты сбрасываются в ноль, затем 0-й бит становиться равным текущему значению chan.

Текущий определяет какой канал сейчас, предыдущее значениенужно для определение старшее или младшее слово принято.
Что тут не так? Если Вы знаете другой способ определения какое слово какого канала было принято (или должно быть передано, т.к. в передатчике у меня тот-же алгоритм, и оно прекрасно работает) - расскажите, буду весьма благодарен. Хотя в любом случае проблема у меня не в этом.

В любом случае, если бы был неправильный порядок бойт (слов) было бы пол беды, но там сами байты неправильные. И периодически выскакивает frame error, ]хотя и когда не вскакивает, принятые байты все равно не правильные (т.е. белибелрда, после каждого ресета разная, но после ресета - все время одинаковая).
drum1987
сори не заметил строку
sequence |=1;
Allregia
Кстати, я еше не пойму важно ли в каком порядке считывать статус (SR) и данные (DR) ?
drum1987
Попробуйте в прерывании еще проверять флаг RXNE...
Вот пример из либы:
Код
void SPI2_IRQHandler(void)
{
  /* Check the interrupt source */
  if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET)
  {
    /* Store the I2S2 received data in the relative data table */
    I2S2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2);
  }
}
у меня прерывание по АЦП срабатывало намного чаще чем происходило прерывающее событие
Allregia
Попробую, хотя - другие источники преывания коме RXNE у меня не вкюлчены, не должно срабатывать.
Allregia
Что-то страннно, сделал перекомпиляцию всей программы - на 48к заработало, без единого сбоя!
Попробовал переключить на 96к и выше - периодически выскакивает frame error, т.е. получается приемник не успевает где-то вовремя почитать принятое, и синхронизация сбивается. Передача по прежнему идет правильно (судя по сигналам на шине).

Приоритет прерываний - у передатчика 0, у приемника 1.
Завтра попробую наоборот, хотя по идее времени и летенси должно хватать в любом случае.
Allregia
Пришлось в конце прерывания поставить
__ISB();

с ним заработало на 96, а вот на 192 все равно глючит.
aaarrr
Цитата(Allregia @ Mar 6 2013, 18:29) *
с ним заработало на 96, а вот на 192 все равно глючит.

И охота прерываться на частоте 384кГц? Подключили бы давно DMA.
Allregia
Цитата(aaarrr @ Mar 6 2013, 16:58) *
И охота прерываться на частоте 384кГц?


И это повод для глюков? sm.gif
Мне в реалтайме нужно кое-какую обработку делать, она прекрасно успевает, если только приемник нормально заработает.
Проблема-то не во времени, а в кривом I2S слейве у ST.
(уже за то, что они по два прерывания на каждый канал дают, да еще без бита-признака старшее/младшее полуслово, их всех расстрелять как вредителей надо sm.gif,, неужели не могли как у NXP передавать 32-х битное слово? не говоря уже о хотя бы промежуточном регисте, илитем более фифо!)

Цитата
Подключили бы давно DMA.


Попробую, тем более что приятель подсказал мне как совместить и ДМА и ту обработку, что мне надо. Но проблем в том, что у него с ДМА приемник-слейв в 96 работает (ему больше пока и не надо), а на 192 и у него глючит.
aaarrr
Цитата(Allregia @ Mar 7 2013, 02:47) *
И это повод для глюков? sm.gif

Нет, просто подход показался странным: 192кГц процессором - это уже 768кГц прерываний, или ~200 тактов между прерываниями на частоте 150МГц.
Даже если и успевает, прорва ресурса вылетает в трубу.

Цитата(Allregia @ Mar 7 2013, 02:47) *
Попробую, тем более что приятель подсказал мне как совместить и ДМА и ту обработку, что мне надо. Но проблем в том, что у него с ДМА приемник-слейв в 96 работает (ему больше пока и не надо), а на 192 и у него глючит.

Попробуйте. Я гонял I2S в слейве на STM'ах, но тоже только на 96. Выше просто нужды не было.
Allregia
Цитата(aaarrr @ Mar 7 2013, 01:11) *
Нет, просто подход показался странным: 192кГц процессором - это уже 768кГц прерываний, или ~200 тактов между прерываниями на частоте 150МГц.


На самом деле сейчас еще хуже - это ДВА прерывания, каждое из которых 768кгц.
Каждое из них длиться примерно 0.25мкс.

Цитата
Даже если и успевает, прорва ресурса вылетает в трубу.

Половина, примно sad.gif А с ДМА - четверть памяти вылетает в трубу. Но мне уже подсказали как решить эту поблему, поэтому буду итди на ДМА.
Я только пока не очень понял - могут ли два стрима одного канала одного контоллера работать одновременно ? (т.е. оба i2s2 и i2s3)

Цитата
Попробуйте. Я гонял I2S в слейве на STM'ах, но тоже только на 96. Выше просто нужды не было.

Ну придется и мне ограничиться 96, если не получится выше, но хочется использовать все возможности.
Allregia
Что-то у меня не получается I2S3 Master in DMA запустить.
Делаю так:
CODE
static void I2S3_DMAInit( void )
{
DMA_InitTypeDef DMA_InitStruct;

DMA_Cmd( DMA1_Stream5, DISABLE );
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(SPI3->DR); // I2S Data
DMA_InitStruct.DMA_Memory0BaseAddr = (u32)&DMABUF[0]; // memory start
DMA_InitStruct.DMA_BufferSize = DMABUF_SIZE; // length

DMA_InitStruct.DMA_Channel = DMA_Channel_0;
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; // direction
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16 bit per
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16 bit memory
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; // circ
DMA_InitStruct.DMA_Priority = DMA_Priority_High; // prority
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Enable; // DMA_FIFOMode_Disable;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_INC4; //DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

while( DMA_GetCmdStatus( DMA1_Stream5 ) == ENABLE ); // wait for the last DMA end
DMA_Init( DMA1_Stream5, &DMA_InitStruct ); // Init New
}

//далее инитю i2s точно также, кака я его инитил при работе по прерываниям, только добавил несколько строк:

I2S_Init(SPI3, &I2S3_InitStructure);
I2S3_DMA_Init(); // <<<<<<<<<<<<<<< добавил

SPI_I2S_DMACmd( SPI3, SPI_I2S_DMAReq_Tx, ENABLE); // <<<<<<<<<<<<<<< добавил

I2S_Cmd(SPI3, ENABLE);
DMA_Cmd( DMA1_Stream5, ENABLE ); // <<<<<<<<<<<<<<< добавил


Передача не идет, i2s молчит. Может ему какой "стартовый пинок" еще дать надо, или у меня порядок вызовов Cmd не правильный?

Ой, ложная тревога, "дело было не в бобине" - все работает. Код оставлю, может кому пригодится.
Allregia
Но обнаружил другую проблему - случайно проинитил все два раза подряд, и... сдвинулись передаваемые слова между каналами!
Старшее слово левого стало младшим правого и т.д.
Почему при переинициализации все не сбросилось?
Но достаточно было поставить между двумя оинаковыми инициализациями задержку 5мс - глюк пропал. Почему?
Allregia
В общем, сделал я и передачу и прием по DMA. Процессор посли инициализации вооще ничего не делает (while(1)wink.gif, кроме прерывания от системного таймера.
На 48 и 96 - все идеально, 192 - не работает, постоянная ошибка синхронизации.
Я уже в шоке - у меня идеи кончилисьsad.gif
aaarrr
Цитата(Allregia @ Mar 9 2013, 21:13) *
На 48 и 96 - все идеально, 192 - не работает, постоянная ошибка синхронизации.
Я уже в шоке - у меня идеи кончилисьsad.gif

Ну, может, оно и не умеет на 192 в слейве работать? В даташите до сих пор стоят умилительные TBD вместо таймингов.
Allregia
Цитата(aaarrr @ Mar 9 2013, 21:28) *
Ну, может, оно и не умеет на 192 в слейве работать? В даташите до сих пор стоят умилительные TBD вместо таймингов.


Может и не умеет, это весьма печально, потому что тогда у меня сильно ограничиться область применения устройства.
В даташите много чего непонятно, например почему в делителе частоты i2s нельзя ставить ни 0 ни 1, только начиная с 2. Если почему нельзя 0 понятно, то почему нельзя 1 - нет.
Кстати, хотья они пишут что нельзя, но с 1-й там оно тоже на 96К прекрасно работает.

Тайминги есть в даташите на F2, и я не думаю что у F4 этот блок чем-то отличается. Да и по логике - представляя немножко как оно внутри устроено, работа на 192 не должна чем-то отличаться от работы на 96, это еще не те частоты, где может что-то повлиять на работу обычного сдвигового регистра и его обвязки.

Но может я что-то упускаю, и в программе есть баг? Что раньше надо - разрешать DMA или разрешать I2S? Я, правда, пробовал и так и так, разницу не заметил. Или может флажек какой-то надо срасывать? Сама передачи и прием идут совершенно устойчиво - если принимает неправильно, то оно "неправильно" всегда по одинаковому, т.е. конкретно переданная константа принимается неправильным значением, но таким-же константным. Сбоев в процессе передачи-приема нет, проблем только в начальной синхронизации приемника с LRCLK.

Может это вообще аппратная проблема, и надо на шину попробовать 10-20пф конденсаторов навешать?
Allregia
Только что звонил приятель, который параллельно со мной занимается своим проектом с i2s на F4.
У него та-же проблема с 1796/192, но сейчас он рассказал что случайно залил программу с одной тестовой платы в другую (на одной клок I2s 24мгц, на другой 49) - оказалось оно прекрасно работает на 384кгц, хотя это полный Out Of Spec, еще и делитель =1, что в даташите написано "forbidden" (я тоже замечал, что на 192 с делителем=1 мастер-передатчик работает прекрасно, а в слейв-приемнике ни внешний клок ни делитель не участвуют).

Передача вообще прекрасная, прием - примерно 5% сбоев синхронизации, при том что на 192 и у него и у меня примерно 95% сбоев!
Uuftc
Цитата(Allregia @ Mar 10 2013, 02:46) *
В даташите много чего непонятно, например почему в делителе частоты i2s нельзя ставить ни 0 ни 1, только начиная с 2. Если почему нельзя 0 понятно, то почему нельзя 1 - нет.
Кстати, хотья они пишут что нельзя, но с 1-й там оно тоже на 96К прекрасно работает.

Там начинаются странности с DIV 1 и ODD 1
Вообще впечатление такое, что в доке просто забили описывать все "странности" I2S, коих у STM32F куча.
Цитата(Allregia @ Mar 10 2013, 02:46) *
Сама передачи и прием идут совершенно устойчиво - если принимает неправильно, то оно "неправильно" всегда по одинаковому, т.е. конкретно переданная константа принимается неправильным значением, но таким-же константным. Сбоев в процессе передачи-приема нет, проблем только в начальной синхронизации приемника с LRCLK.

В errata на stm32f4 было нечто похожее
Allregia
Цитата(Uuftc @ Mar 12 2013, 03:46) *
Там начинаются странности с DIV 1 и ODD 1


Самое интересное, что при DIV=1 ODD=0 все прекрасно работает, даже с разгонгом по частоте.
Почему они запрещают DIV=1 непонятно.

Цитата
Вообще впечатление такое, что в доке просто забили описывать все "странности" I2S, коих у STM32F куча.

В errata на stm32f4 было нечто похожее


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

P.S. В эррате на F2 было еще веселее, из нее ясно видно что в них I2S-Slave в принципе нерабочий. В F4 подправили, но не до конца.

P.S. Интересно - каку. макимальную частоты можно подать на вход внешнего клока? 49мгц переваривает отлично, переварит ли 98? (у меня нечем пока проверить).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.