Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: ATMega8535 SPI Slave Mode trouble
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Yurik32
С одной стороны ARM (SPI Master), с другой ATMega8535L. (Тактируется внутренним RC - 8Мгц)
Частота SPI - 1МГц.

Проверяю как. Беру отправляю байт с АРМа, и ожидаю каких то
импульсов на PORTD.7/ PORTD.6 AVRa. Их конечно же нету.

на ARMе получаю первый байт 0b11001100. как и ожидалось. а
последующее - тэ которые посылал с АРМа. Тоесть данные возвращаются,
что свидетельствует о том что они не были программно принятые в AVRе.

Исходний код AVRа (проект в CodeVisionAVR):
Код
#include <MEGA8535.H>
#include <stdio.h>
#include <delay.h>

#include "header.h"

interrupt [SPI_STC] void spi_isr(void)
{
    unsigned char data;  
        PORTD.6 = 0;    
        PORTD.6 = 1;
// Clear the SPI interrupt flag
#asm
    in   r30,spsr
#endasm
        data = SPDR;            
        PORTD.6 = 0;
}

void main(void)                                        
{
    unsigned char tmp;

    #asm ("cli") //Выкл. глоб. прерывания
    
    // Input/Output Ports initialization
    // Port A initialization
    PORTA=0x00;      
    DDRA=0x00;
    // Port B initialization
    PORTB=0x00;
    DDRB=0b00000111;
    // Port C initialization
    PORTC=0x00;
    DDRC=0xFF;
    // Port D initialization
    PORTD=0x00;
    DDRD=0b11000000;    
    
    // SPI initialization              
    /* Set MISO output */    
    DDRB.6 = 1; //DDR_SPI = (1<<DD_MISO);

// SPI initialization
// SPI Type: Slave
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First

//    SPCR=0xC0;
    SPCR=0x80;    
    SPSR=0x00;

// Clear the SPI interrupt flag
#asm
    in   r30,spsr
    in   r30,spdr
#endasm

/* Enable SPI */
SPCR |= (1<<SPE);
    
    
// Global enable interrupts
#asm("sei")
        
    while (1)
    {        
        SPDR = 0b11001100;        
        
        /* Wait for reception complete */
        while(!(SPSR & (1<<SPIF))) {};       //   <<< ---  Такое ощущение, что здесь программа уходит в ступор

        tmp = SPDR;                                              
        tmp = SPSR;
        tmp = tmp & 0b10000000;                
        if (tmp)
        {                
                PORTD.7 = 0;    
                PORTD.7 = 1;    
                PORTD.7 = 0;      
        }        
                
//        delay_ms(1000);      

    };
}


Что я делаю не так ? Есть какие то идеи ?
Nikson1200
меня смущает одновременное использование (в одной программе в смысле) обработчика прерывания, где сбрасываем флаг SPIF и цикла, который крутится пока флаг SPIF сброшен...
SysRq
Цитата(Yurik32 @ Nov 12 2008, 01:53) *
// Clear the SPI interrupt flag
#asm
in r30,spsr
#endasm
Не надо этого.
Цитата
SPIF is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively, the SPIF bit is cleared by first reading the SPI Status Register with SPIF set, then accessing the SPI Data Register (SPDR).


Цитата(Yurik32 @ Nov 12 2008, 01:53) *
while(!(SPSR & (1<<SPIF))) {}; // <<< --- Такое ощущение, что здесь программа уходит в ступор
У вас ведь разрешено прерывание от SPI, и разрешены прерывания глобально. Как только SPIF взводится - вызывается прерывание и его сбрасывает. Оставить что-то одно может?

На SS должен быть низкий уровень.
Yurik32
Цитата(SysRq @ Nov 12 2008, 02:24) *
Не надо этого.

Убрал.

Цитата(SysRq @ Nov 12 2008, 02:24) *
На SS должен быть низкий уровень.

Все сигналы генерируются верно. Смотрел осциллографом.

Сделал только на прерывании - не работает, потом переделал только на полинге SPIF - тож не работает. Симптомы те же. Я уж прям не знаю к чему придраться. Начинаю грешить на контроллер. Завтра на другом(ATMega16) попробую сделать.
VladimirYU
Цитата(Yurik32 @ Nov 12 2008, 01:53) *
С одной стороны ARM (SPI Master), с другой ATMega8535L. (Тактируется внутренним RC - 8Мгц)
Частота SPI - 1МГц.


/* Wait for reception complete */
while(!(SPSR & (1<<SPIF))) {}; // <<< --- Такое ощущение, что здесь }[/code]

Что я делаю не так ? Есть какие то идеи ?


У меня один раз было на двух мегах 128-ых из одной партии:
После выхода из while у SLAVE в SPDR проскакивала всякая хрень, ошибка была в бите который мастер выталкивал последним. Посмотрел осциллом передачу от Мастера и ох...ел, 7 битов вытакивались равномероно с частотой клоков, как положено, а последний бит выталкивался (и последний 8-ой клок) после паузы примерно на время передачи байта, а следующий байт сообщения от Мастера шел сразу за последним битом. У слэйва крыша съезжала. Обошел следующим образом: вставил задержку у мастера между посылками байтов - помогло. Потом в следующей версии ПО передачу от мастера сделал по прераванию от SPIF и подобной прооблемы не было. В последующих приборах проверял обе версии ПО для Мастера, больше этот косяк не всплывал. В итоге списал все на глюк в конкретной меге.
Yurik32
Сегодня пробовал сделать на другом ATMega8535(из другой партии), и эщо на ATMega16. Результат тот же.
Получается что проблема все таки программная.

Тестировал такой код:
Код
#include <MEGA8535.H>

void main(void)
{
    unsigned char tmp;

    #asm ("cli") //Выкл. глоб. прерывания

// Input/Output Ports initialization
// Port A initialization
    PORTA=0x00;
    DDRA=0x00;
// Port B initialization
    PORTB=0x00;
    DDRB=0b00000111;
// Port C initialization
    PORTC=0x00;
    DDRC=0xFF;
// Port D initialization
    PORTD=0x00;
    DDRD=0b11000000;

// SPI initialization
    /* Set MISO output, all others input */
    DDRB.6 = 1; //DDR_SPI = (1<<DD_MISO);

    SPCR=0x00;

// Clear the SPI interrupt flag
    #asm
        in   r30,spsr
        in   r30,spdr
    #endasm

/* Enable SPI */
    SPCR |= (1<<SPE);

// Global enable interrupts
    #asm("sei")

    while (1)
    {
        SPDR = 0b11001100;

        /* Wait for reception complete */
        while(!(SPSR & (1<<SPIF))) {};

        PORTD.6 = 1;
        PORTD.6 = 0;
        tmp = SPDR;                                              
        if (tmp == 0x81)
        {                
                PORTD.7 = 1;    
                PORTD.7 = 0;      
        };
    };
}


чтобы прояснить сложившуюся картину выложу Немного осциллограмм.

Ето ЧипСелект и Клок который генерирует Мастер (ARM):


Мастер постоянно передает посылку из 2 байт
Первый байт (0x81):

Второй байт (0x1e):



От АВРа получаю:
Первый байт:


Второй байт:


Третий байт:


Четвертый байт:


Тоесть если ресетнуть АВР то тогда в ответ на первую посылку получу первый и второй байт,
на вторую посылку - третий и четвертый байты, на третюю посылку снова получу третий и
четвертый байты ну и т.д.
Отсюда хорошо видно что третий и четвертый байты ето те которые посилал Мастер. Получается что все возвращается назад к АРМу.

Методом научного втыка нашел причину. Виной всему было вот ето:

while (1)
{
SPDR = 0b11001100;

/* Wait for reception complete */


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

Вот исходный код преривания SPI:
Код
interrupt [SPI_STC] void spi_isr(void)
{
    unsigned char data;  
        PORTD.6 = 1;
    data = SPDR;            

        if (data == 0x81)
        {                
                PORTD.7 = 0;    
                PORTD.7 = 1;    
                PORTD.7 = 0;      
        };            
        
        if (data == 0x1e)
        {                
                PORTD.7 = 0;    
                PORTD.7 = 1;    
                PORTD.7 = 1;    
                PORTD.7 = 1;    
                PORTD.7 = 1;                                    
                PORTD.7 = 0;      
        };            

        PORTD.6 = 0;            
}


Мастер постоянно посылает посылку из 2 байт. Первый байт - 0x81. Второй - 0x1e. Тоесть сначала мы должны
увидеть узкий импульс на PORTD.7 а потом шырокий.

А ето осциллограммы.



И с них четко видно что все наоборот. Тоесть в прерывании я получаю байт который физически был принят ещо в момент
предыдущей пересылки.

Это должно так быть ? Или снова какая то ерунда ?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.