dFi.w = F*167.77216; //частота передаваемая через SPI, какое-то фиксированное число 167.77216 PORTB &= ~_BV(PB0); SPI_MasterTransmit(Cnt & 0x03);//0x03-маска SPI_MasterTransmit(dFi.b[0]);//флаги передачи SPI_MasterTransmit(dFi.b[1]);//флаги передачи SPI_MasterTransmit(dFi.b[2]);//флаги передачи
Боюсь, что dFi.w не dFi.w, a &Fi.w (указатель, а [0], [1] ... - индекс для ячейки для double переменных. Иначе я без побитового сдвига понятия не имею, как можно получить частоту в 3 байта, тем более со десет. знаком (F*167.77216). А и какой double, в Вашем компиляторе для этого МК вероятно double -> float (32 bit). Портировать код с другого МК на этот?
Последний раз редактировалось veso74 Пт июн 09, 2023 15:03:36, всего редактировалось 4 раз(а).
Начал менять настройки мастера, изменил прескейлер в регистре SPI SPCR с 16 до 128, при частоте CK - 7813 Гц и заработал 3 кейс.MOHCTEP был прав, осталось разобраться с как настроить частоту, чтобы работали все 4 кейса USI_OVERFLOW. Но пока что ка как бы я не настраивал частоту мастера, 4 кейс оживить не удается.
Добавлено after 2 minutes 33 seconds: veso74, это прошивка с рабочего прибора, прошивка с слейва не сохранилась и сгорела в результате КЗ. Скинул архив, иницилизация SPI в USART.c. Слейв в данной ситуации выступает как регулируемый генератор меандра.
После некоторых изменений, таких как перенос из for функции инициилизации USI и изменения прескейлера частоты тактирующего сигнала мастера, МК в протеусе начал реагировать на измения номера ножки и частоты со стороны мастера. Теперь 1 байт(номер ножки, отправляемый со стороны мастера) определяется корректно и на заданной ножке генерируется частота, но частота не соответствует заданной и форма генерируемой частоты далека от меандра. Я думаю, что это связано с тем что кейс 3 по прежнему не работает, также пробовал подавать 2-х байтные и 1-байтные числа по SPI со стороны мастера и все равно частота на выходе МК ATtiny2313 не корректна. На данный момент присутствует 3 основные проблемы: 1) Неверная частота на выходе МК. 2) Неверная форма сигнала, должен быть меандр. 3) Хоть и частота генерируется на верной ножке, почему-то МК подает +5В на другие ножки, которые задействованы как выводы частоты nG, а этого быть не должно. Вот актуальный код слейва: Спойлер
#define CS PORTD3 // Chip select #define DO PORTB5 // MISO or Data Out #define USCK PORTB7 // Clock
typedef union { unsigned long int w; // w as WORD unsigned int h[2]; // h as HALF-WORD unsigned char b[4]; // b as BYTE } Union32;
Union32 dFi;
unsigned int fG; unsigned char nG; unsigned int N[]={1,8,64,256,1024}; unsigned char flag_RT = 0; unsigned char ch_num = 0;
volatile char reqID = 0; // This is for the first byte we receive, which is intended to be the request identifier //volatile unsigned char index = 0; // this is to send back the right element in the array
void SpiSlaveInit() { #asm("cli") USICR = ((1<<USIWM0)|(1<<USICS1)); // Activate 3- Wire Mode and use of external clock but NOT the interrupt at the Counter overflow (USIOIE) PORTD |= (1<<6); PORTD |= 1<<CS; // Activate Pull-Up resistor on PD3 GIMSK |= 1<<INT1; MCUCR |= 1<<ISC10; #asm("sei") }
// External Interrupt 0 service routine interrupt [EXT_INT1] void ext_int1_isr(void) { if((PIND & (1<<CS))== 0){ PORTD |= (1<<5); // If edge is falling, the command and index variables shall be initialized // and the 4-bit overflow counter of the USI communication shall be activated: reqID = 0; //index = 0; flag_RT = 0; USICR |= (1<<USIOIE); USISR = 1<<USIOIF; // Clear Overflow bit } else{ // If edge is rising, turn the 4-bit overflow interrupt off: USICR &= ~(1<<USIOIE); PORTD |= (1<<6); } }
Открыта удобная площадка с выгодными ценами, поставляющая весь ассортимент продукции, производимой компанией MEAN WELL – от завоевавших популярность и известных на рынке изделий до новинок. MEAN WELL.Market предоставляет гарантийную и сервисную поддержку, удобный подбор продукции, оперативную доставку по России.
На сайте интернет-магазина посетители смогут найти обзоры, интересные статьи о применении, максимальный объем технических сведений.
VFG_DDR тоже настройте один раз, при инициализации. Тогда set_out_pin (nG); будет не нужна. Вместо ее вызова, в бесконечном цикле достаточно будет строки nG=1<<ch_num;
Продукция MOSO предназначена в основном для индустриальных приложений, использует инновационные решения на основе более 200 собственных патентов для силовой электроники и соответствует международным стандартам. LED-драйверы MOSO применяются в системах наружного освещения разных отраслей, включая промышленность, сельское хозяйство, транспорт и железную дорогу. В ряде серий реализована возможность дистанционного контроля и программирования работы по заданному сценарию. Разберем решения MOSO
подробнее>>
warptred12
Заголовок сообщения: Re: Проблема при связи SPI и USI AT90CAN128 и Attiny2313
MOHCTEP, тогда при nG = 0 на мастере(0x00000000), частота генерируется на ножках PB0 и PB1.
Добавлено after 3 minutes 50 seconds: При nG = 1(0x00000001), частота генерируется на ножке PB1, при nG = 2(0x00000002), частота генерируется на ножке PB2.
typedef union { unsigned long int w ; // w as WORD unsigned int h[2]; // h as HALF-WORD unsigned char b[4]; // b as BYTE } Union32; Union32 dFi;
объединение - каждый элемент (w,h,b) начинается с одной и тойже ячейки памяти, т.е. dFi.b[0] - это младший байт из dFi.w
dFi.w = F*167.77216; - здесь неявное преобразование float->long int (как компилятор это делает я не знаю, допустимо ли выбрасывать старший байт)
в передаче: SPI_MasterTransmit(Cnt & 0x03); //1-й байт SPI_MasterTransmit(dFi.b[0]); //2-байт - младший из dFi.w SPI_MasterTransmit(dFi.b[1]); //3-байт - второй из dFi.w SPI_MasterTransmit(dFi.b[2]); //4-байт - третий из dFi.w, четвертый из dFi.w - проигнорирован, не передается, т.е. целостность unsigned long int w нарушается
при приеме: ch_num = USIDR; dFi.b[1] = USIDR; - младший из dFi.w dFi.b[2] = USIDR; - второй из dFi.w dFi.b[3] = USIDR; - третий из dFi.w
т.е. в fG <b[1]><b[1]><b[0]>< 00 > (здесь b[] - из dFi.w передатчика) а в dFi.w <b[3]><b[2]><b[1]><b[0]>
Добавлено after 11 minutes 45 seconds: а между тем, если б передавать 5 байт (номер, float) результат вычисления переправлялся бы целёхоньким dFi.f = F*167.77216; - без преобразования типа
typedef union { float f; unsigned long int w ; // w as WORD unsigned int h[2]; // h as HALF-WORD unsigned char b[4]; // b as BYTE } Union32;
SPI_MasterTransmit(Cnt & 0x03); //1-й байт SPI_MasterTransmit(dFi.b[0]); //2-байт - младший из dFi.f SPI_MasterTransmit(dFi.b[1]); //3-байт - второй из dFi.f SPI_MasterTransmit(dFi.b[2]); //4-байт - третий из dFi.f SPI_MasterTransmit(dFi.b[3]); //5-байт - четвертый из dFi.f
и ничего не надо ручками склеивать в приемнике dFi.f = dFi.f передатчика, он же fG
a797945, а вот как этот 3 байт ловить не понятно, в прерывании программа не доходит до case 3. Вероятно отправляются 4 байта вместо 5 - для экономии памяти attiny. Частота SCK задана минимальной на мастере(прескейлер 128/7813Гц). Не понимаю как мне подогнать Attiny под частоту тактирования мастера.
я не специалист, и тем паче не специалист по avr, мне сложно Вам что-то советовать связанное со структурой МК или его перефирией. если Вы предполагаете нехватку ресурсов на слейве, попробуйте (для эксперимента) отправлять на слейв фиксированные "частоты", идея в том чтоб наладить передачу и генерацию, а математику со слейва пока убрать эту: for(i=0;i<=4;i++) { TimDiv = (F_CPU/(2*(Foc/167.77216)*N[i])-1)+0.5; if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){ ClockSelect=i+1; break; } } т.е. посчитать несколько значений для таймера(ов) слейва, мастером эти значения (через паузу или по кнопке) отсылать на слейв, там принимать и без математики просто записывать в таймер(а).
Проблема довольно сильно затянулась и до сих пор не удалось отладить в железе прошивку на attiny2313, так что я решил параллельно заниматься написанием прошивки на контроллер с полноценной поддержкой SPI ATMEGA8. Код слейва: Спойлер
if (countSPIb >= sizeof(master_arr)) { // если кончился массив PORTC |= (1<<2); countSPIb = -1; // обнуляем счетчик и ждем следующий обмен } } // Конец SPI - пришел байт
void SetUpTim1A(unsigned long int Foc) //calculate value OCR1A register { unsigned long int TimDiv; unsigned char ClockSelect=0; unsigned char i=0; for(i=0;i<=4;i++) { TimDiv = 1*((F_CPU/(2*Foc*N[i])-1)); if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){ ClockSelect=i+1; break; } } #asm("cli") OCR1A=TimDiv; TCCR1B = (1<<WGM12) | (ClockSelect<<CS10); #asm("sei") }
void UpdateTim1A(unsigned long int freq) //old value storage { static unsigned long int fG_old = 0; if (fG_old != freq) { SetUpTim1A(freq); fG_old = freq; } }
void main(void) { static unsigned long int fG_old = 0; unsigned long int tmp; int i; VFG_DDR = 0b00000111; DDRC = 0b11111111; setup(); Tim1Init(); #asm("sei") for(;;) { if(PINB.2==0) {countSPIb = -1;} //сброс в случае глюка связи
if (fG_old != fG) { //old value detction SetUpTim1A(fG); fG_old = fG; }
for (i = 0; i < sizeof(master_arr); i++) { nG = master_arr[i]; //generator number fG = master_arr[i] << 8; tmp = master_arr[i] << 16; fG |= tmp; tmp = master_arr[i] << 24; fG |= tmp; //generator frequency UpdateTim1A(fG); SetUpTim1A(fG); } } }
Мне кажется этот код интуитивно более понятен и будет проще его отладить, хотябы в протеусе, чтобы были дополнительные варианты в случае неудачи с аттини. Ну проблема в том, что программа записывает только первый байт информации(nG - выбор выходной ножки котроллера), а в остальные записывает нули, так что вопрос к экспертам, где я облажался?
Добавлено after 38 minutes 21 second: Теперь работает только PC0 и на нем частота 32 Гц, хотя ничего не менял в коде.
MOHCTEP, первый полученный байт по SPI, я присваиваю значению массива master_arr[0], а это значение присваиваю переменной nG(номер выхода генератора), master_arr[1],master_arr[2],master_arr[3] я пытаюсь присвоить переменной fG(частота генератора, подставляемая в формулу расчета регистра OCR1A). Идея такова, что каждое прерывание я записываю по байту информации в массив master_arr[i], а в основном цикле я пытаюсь присвоить эти значения переменным nG и fG. Ну такова была идея по крайней мере.
Добавлено after 3 minutes 21 second: Функция for (i = 0; i < sizeof(master_arr); i++) нужна для того чтобы подставить эти значения в правильном порядке, но опят таки я не уверен что это работает правильно.
Нет. Вы циклом всегда присваиваете каждый байт массива, по очереди, обеим переменным сразу. В итоге, после отработки этого странного цикла, обеим переменным будет присвоен последний байт массива. Уберите этот цикл и модифицируйте переменные обращаясь к массиву по числовым индексам master_arr[0],master_arr[1]... и master_arr[3](четвертый байт) вам недоступен, так как длина массивов у вас = 3 байтам.
if (countSPIb >= sizeof(master_arr)) { // если кончился массив PORTC |= (1<<2); countSPIb = -1; // обнуляем счетчик и ждем следующий обмен } } // Конец SPI - пришел байт
void SetUpTim1A(unsigned long int Foc) //calculate value OCR1A register { unsigned long int TimDiv; unsigned char ClockSelect=0; unsigned char i=0; for(i=0;i<=4;i++) { TimDiv = 1*((F_CPU/(2*Foc*N[i])-1)); if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){ ClockSelect=i+1; break; } } #asm("cli") OCR1A=TimDiv; TCCR1B = (1<<WGM12) | (ClockSelect<<CS10); #asm("sei") }
void UpdateTim1A(unsigned long int freq) //old value storage { static unsigned long int fG_old = 0; if (fG_old != freq) { SetUpTim1A(freq); fG_old = freq; } }
void main(void) { static unsigned long int fG_old = 0; unsigned long int tmp; int i; VFG_DDR = 0b00000111; DDRC = 0b11111111; setup(); Tim1Init(); #asm("sei") for(;;) { if(PINB.2==0) {countSPIb = -1;} //сброс в случае глюка связи
if (fG_old != fG) { //old value detction SetUpTim1A(fG); fG_old = fG; }
Ну... сложно что то умное подсказать на расстоянии, да еще и для протеуса. В качестве версии: проблема возможна в том, что вы постоянно перестраиваете переменные nG и fG в главном цикле и вместе с ними таймер. Независимо от того - пришло там что-то по SPI или нет. Возможно ваш таймер, от постоянных перенастроек, просто не успевает нормально отрабатывать цикл. Вот у вас есть счетчик заполнения массива countSPIb. Можно, к примеру, в майн цикле проверять его на равенство длине массива (это значит, что пришли все 5 байт от мастера и данные подготовлены) и только в этом случае пересчитать переменные + таймер и сбросить счетчик countSPIb, подготовившись к следующему приему. Как-то так примерно...
MOHCTEP, в протеусе мастер отправляет верные данные, в хексадермальном формате 02 5C 8F 02(первый байт номер генератора, остальные 3 значения частоты), а вот в ответ мастеру - слейв шлет 00 01 01 01 в ответ, это значит, что по какой-то причине, байты, полученные от мастера записываются в единицы. Если я правильно понимаю, как работает SPI, то при получении байта, слейв отправляет полученный байт мастеру, в неизмененном виде, а у меня не так получается. Это значит что скорее всего код в прерывании криво написан, но пока конкретно не ясно, что там не так.
Добавлено after 7 minutes 56 seconds: А для хранения значения переменной fg, у меня есть такая функция, которая сравнивает старое и новое значение и не изменилось ли значение fG Спойлер
Код:
void UpdateTim1A(unsigned long int freq) //old value storage { static unsigned long int fG_old = 0; if (fG_old != freq) { SetUpTim1A(freq); fG_old = freq; } } if (fG_old != fG) { //old value detction SetUpTim1A(fG); fG_old = fG; }
Добавлено after 4 minutes 34 seconds: Еще может быть проблема в том, чт переменная fG - 32-х битная(unsigned long int), а мы записываем в нее 24 бита. Но я даже не знаю как это проверить, просто предположение.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения