Скетч для проверки работоспособности портов и EEPROM

Immortal
Offline
Зарегистрирован: 28.12.2013

Написал универсальный скетч для проверки работоспособности портов и EEPROM памяти. Ищутся добровольцы для проверки в железе и доработки тестовой программы. Мой код проверен на ATmega128A, ATmega8A при этом никаких правок в коде делать не нужно. Количество цифровых и аналоговых выводов определяется автоматически.

Что еще нужно сделать:

1. Проверка аппаратных прерываний, таймеров, прерываний по переполнению таймера.

2. Прошивка на асме для проверки RAM, Stack Pointer Register, Status Register, регистров R0-R25, X,Y,Z

Что уже было сделано: Мой код при запуске ничего не делает, он ждет команду по UART. В терминал нужно отправить одну английскую букву для запуска нужного теста. Когда какой то тест был запушен, чтобы его прервать нажмите кнопку ресет. Список комманд:

v - Выводит версию программы и краткое описание доступных тестов.

a - АЦП тест. Выводит значения всех аналоговых входов. Для этого вы подключаете переменный резистор поочередно к каждому аналоговому входу и смотрите как меняются значения.
i - Inputs test. В этом тесте включена подтяжка всех входов (INPUT_PULLUP). Тест выводит значения всех входов с низким уровнем на них. Вы берете провод подключенный на землю и через резистор 1КОм по очереди качаетесь каждого входа, в терминале должна появиться только одна надпись LOW с номером вывода. Этот тест позволяет найти замкнутые между собой пины или дорожки с обрывом (а также выводы со сгоревшими внутренними PULLUP резисторами)
o - Outputs test. Устанавливает все порты как выход с 1 на них. Вы берете тестер или светодиод с резистором и проверяете наличие высокого уровня на каждом выходе.
b - Blink. Тест наплатного светодиода.
0 - ZEROFILL встроенного EEPROM (тоесть заполнение нулями 0x00 во все ячейки). Тест закончится, когда будет выведено "Done" в консоль. После этого запустите комманду "e" для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
1 - 0xFF заполнение встроенного EEPROM. Тест закончится, когда будет выведено "Done" в консоль. После этого запустите комманду "e" для вывода содержимого EEPROM в консоль и проверьте нет ли бытых ячеек
p - Тест ШИМ на наплатном светодиоде. Тест надо полностью переписать, текущая реализация мне не нравится.

e - Выводит все содержимое EEPROM в терминал.

Цифровые порты 0 и 1 не тестируются. Этот тест предполагает, что выводы 0 (RX) и передачи данных 1 (TX) данных в порядке, раз у вас получилось загрузить скетч.

Код состоит из двух файлов. Последняя версия всегда доступна по ссылке

Файл hwtest.ino

#define FIRST_PIN 2
#define PIN_LED  13

#define DELAY_ITERATION  200
#define DELAY_BW_TESTS  2000
#define DELAY_WARN  5000
#define ADC_NUMSAMPLES 8
int samples[ADC_NUMSAMPLES];

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);
  pinMode(PIN_LED, OUTPUT);
}

void loop() {
  digitalWrite(PIN_LED, LOW);
  if (Serial.available() > 0) {

    switch (Serial.read()) {
      case 'v':
        Serial.println("Arduino hardware test v. 1.1b");
        Serial.println("a) ADC MANUAL test. Prints values from all analog pins");
        Serial.println("i) Inputs MANUAL test. Prints all inputs with LOW level on them");
        Serial.println("o) Outputs MANUAL test. Sets all ports to HIGH");
        Serial.println("b) Blink. Tests onboard led");
        Serial.println("0) Zerofill of built-in EEPROM");
        Serial.println("1) 0xFF fill of built-in EEPROM");
        Serial.println("p) Test PWM on on-board LED");
        Serial.println("");
        break;
      
      case 'a': //ADC test Tests all analog pins (A0-A7)
        while(true) {
          Serial.println("ADC test");
          readAnalogValue(A0);
          readAnalogValue(A1);
          readAnalogValue(A2);
          readAnalogValue(A3);
          readAnalogValue(A4);
          readAnalogValue(A5);
          
          #if(NUM_ANALOG_INPUTS == 8)
            readAnalogValue(A6);
            readAnalogValue(A7);  
          #endif
          digitalWrite(PIN_LED, LOW);
          delay(DELAY_BW_TESTS);          
        }
        break;

      case 'i': //Inputs test. Tests all inputs in digital mode
        while(true) {
          Serial.println("Inputs test. Pins in LOW state:");
          for(byte pin = FIRST_PIN; pin <= NUM_DIGITAL_PINS; pin++) {
            pinMode(pin, INPUT_PULLUP);
            if(!digitalRead(pin)) {          
        
              if(pin < 10) Serial.print(" PIN:  ");
              else Serial.print(" PIN: ");
              Serial.print(pin);
              Serial.println(" LOW"); //Should be no "LOW" messages if all pins is not connected to GND
            }
          }
          delay(DELAY_BW_TESTS);
          digitalWrite(PIN_LED, !digitalRead(PIN_LED)); //Toggle LED
        }
        break;

      case 'o': //Outputs test. Tests setting all ports to HIGH
          Serial.println("Outputs test. All set to HIGH");
          for(byte pin = FIRST_PIN; pin <= NUM_DIGITAL_PINS; pin++) {
            pinMode(pin, OUTPUT);
            digitalWrite(pin, HIGH);
          }
        break;
        
      case 'b': //Blink. Tests onboard led
        while(true) {
          Serial.println("Blink");
          digitalWrite(PIN_LED, HIGH);
          delay(1000);
          digitalWrite(PIN_LED, LOW);
          delay(1000);
        }
        break;
        
      case 'e':
        e2reader();
        break;
        
      case '0': //Zerofill of built-in EEPROM
        Serial.println("Zerofill of EEPROM in 5s");
        delay(DELAY_WARN);
        Serial.println("Started");
        for(int i=0; i<EEPROM.length(); i++) {
          EEPROM.write(i, 0);
        }        
        Serial.println("Done");
        break;

      case '1': //0xFF fill of built-in EEPROM
        Serial.println("0xFF Fill of EEPROM in 5s");
        delay(DELAY_WARN);
        Serial.println("Started");
        for(int i=0; i<EEPROM.length(); i++) {
          EEPROM.write(i, 255);
        }        
        Serial.println("Done");
        break;

      case 'p': //Test PWM on on-board LED
        while(true) {
          Serial.println("LED PWM control");
          // fade in from min to max in increments of 5 points:
          for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
            // sets the value (range from 0 to 255):
            analogWrite(PIN_LED, fadeValue);
            delay(40);
          }
        
          // fade out from max to min in increments of 5 points:
          for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
            analogWrite(PIN_LED, fadeValue);
            delay(40);
          }
        }
      break;
    }
  }
}

void readAnalogValue(int adcPin) {    
  int i;
  for (i=0; i<ADC_NUMSAMPLES; i++) {
   samples[i] = analogRead(adcPin);
   delay(60);
  }
 
  // average all the samples out
  int average=0;
  for (i=0; i<ADC_NUMSAMPLES; i++) {
     average += samples[i];
  }
  average /= ADC_NUMSAMPLES;

  Serial.print("ADC PIN: ");
  Serial.print(adcPin);
  Serial.print(" value: ");
  Serial.println(average);
  digitalWrite(PIN_LED, !digitalRead(PIN_LED)); //Toggle LED
}

Файл EEPROM.ino

#include <EEPROM.h>
 
void e2reader(){
  char buffer[16];
  char valuePrint[4];
  byte value;
  unsigned int address;
  uint8_t trailingSpace = 2;
 
  Serial.print("Dumping "); Serial.print(E2END + 1);
  Serial.println(" bytes from EEPROM.");
  Serial.print("baseAddr ");
  for(int x = 0; x < 2; x++){
    Serial.print(" ");
    for(int y = 0; y < 25; y++)
      Serial.print("=");
  }
 
  // E2END is a macro defined as the last EEPROM address
  // (1023 for ATMEGA328P)
  for(address = 0; address <= E2END; address++){
    // read a byte from the current address of the EEPROM
    value = EEPROM.read(address);
 
    // add space between two sets of 8 bytes
    if(address % 8 == 0)
      Serial.print("  ");
 
    // newline and address for every 16 bytes
    if(address % 16 == 0){
      //print the buffer
      if(address > 0 && address % 16 == 0)
        printASCII(buffer);
 
      sprintf(buffer, "\n 0x%05X: ", address);
      Serial.print(buffer);
 
      //clear the buffer for the next data block
      memset (buffer, 32, 16);
    }
 
    // save the value in temporary storage
    buffer[address%16] = value;
 
    // print the formatted value
    sprintf(valuePrint, " %02X", value);
    Serial.print(valuePrint);
  }
 
  if(address % 16 > 0){
    if(address % 16 < 9)
      trailingSpace += 2;
 
    trailingSpace += (16 - address % 16) * 3;
  }
 
  for(int i = trailingSpace; i > 0; i--)
    Serial.print(" ");
 
  //last line of data and a new line
  printASCII(buffer);
  Serial.println();
}
 
void printASCII(char * buffer){
  for(int i = 0; i < 16; i++){
    if(i == 8)
      Serial.print(" ");
 
    if(buffer[i] > 31 and buffer[i] < 127){
      Serial.print(buffer[i]);
    }else{
      Serial.print(".");
    }
  }
}

 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

Тут же на форуме уже был вариант скетча, тестировавшего выводы. :)

Immortal
Offline
Зарегистрирован: 28.12.2013

Да, видел, вот оно - тестилка работоспособности портов и наличия КЗ между выводами:

#define FIRST_PIN 0 // первый вывод
#define LAST_PIN 19 // последний вывод

void Test1(byte pin)
{
  if(pin < 10) Serial.print(" PIN:  ");
  else Serial.print(" PIN: ");
  Serial.print(pin);
  pinMode(pin, OUTPUT);
  digitalWrite(pin, 0);
  Serial.print("    LOW: ");
  if(!digitalRead(pin)) Serial.print("OK  ");
  else Serial.print("FAIL");
  digitalWrite(pin, 1);
  Serial.print("  HIGH: ");
  if(digitalRead(pin)) Serial.print("OK  "); 
  else Serial.print("FAIL");
  pinMode(pin, INPUT);
  Serial.print("  PULL UP: ");
  if(digitalRead(pin)) Serial.print("OK  ");
  else Serial.print("FAIL");
  digitalWrite(pin, 0);
}

void Test2(byte pin)
{
  Serial.print("     ");
  pinMode(pin, OUTPUT);
  digitalWrite(pin, 1);
  delay(5);
  if(!digitalRead(pin))Serial.println("SHORT");
  else Serial.println("OK");
  pinMode(pin, INPUT); 
  digitalWrite(pin, 0);

}

void setup() {
  Serial.begin(9600); 

  Serial.println("Test of short circuit on GND or VCC and between pins:");
  Serial.println();
  for(byte i = FIRST_PIN; i <= LAST_PIN; i++) 
  {
    for(byte j = FIRST_PIN; j <= LAST_PIN; j++) 
    {
      pinMode(j, INPUT);
      digitalWrite(j, 0);
    }
    Test1(i);

    for(byte j = FIRST_PIN; j <= LAST_PIN; j++) 
    {
      pinMode(j, OUTPUT);
      digitalWrite(j, 0);
    }
    Test2(i);
  }

  for(byte j = FIRST_PIN; j <= LAST_PIN; j++) 
  {
    pinMode(j, INPUT);
    digitalWrite(j, 0);
  }
}

void loop() {}

Выводит лог вида:

Test of short circuit on GND or VCC and between pins:
 PIN:  0    LOW: FAIL  HIGH: OK    PULL UP: OK       OK
 PIN:  1    LOW: OK    HIGH: FAIL  PULL UP: FAIL     SHORT
 PIN:  2    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  3    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  4    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  5    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  6    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  7    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  8    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN:  9    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 10    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 11    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 12    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 13    LOW: OK    HIGH: OK    PULL UP: FAIL     OK
 PIN: 14    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 15    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 16    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 17    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 18    LOW: OK    HIGH: OK    PULL UP: OK       OK
 PIN: 19    LOW: OK    HIGH: OK    PULL UP: OK       OK
как видно из лога на 0, 1 и 13 выводах выявлены неисправности - это нормально, потому как 0 и 1 выводы заняты UARTом, а на 13 выводе светодиод.

Не помню кто автор. У меня код больше ориентирован на ручное тестирование, чтоб случайно не попалить выходы на свежераспаянной печатной плате.

maxvalin
Offline
Зарегистрирован: 22.02.2016

Подскажите пожалуйста, как проверить остальные пины на 2560? 

Дело в том что пол дня уже голову ломаю почему не могу нащупать кнопки на ramps 1.4. Уже тестером вызвонил- прямой ход, все точно

35- кнопка энкодера, 41- кнопка стопа(это на дисплее, на выносе с aux4). Обявляю их входами- напряжение ноль((

 Пипец какой то творится.. моск кипит.. Заливаю мерлина - они работают четко(напряжение есть). схему смотрел уже раз 10- скорее всего впал я в цикл, нужен срочный Break

axill
Offline
Зарегистрирован: 05.09.2011

Подход к написанию импонирует, но поясните для чего этот скетч? Для каких задач или ситуаций

особенно потпроверке астроенных систем таких как прерывания. Ищем контроллеры изготовленные кустарным способом?

maxvalin
Offline
Зарегистрирован: 22.02.2016

как это зачем?! 

 вот у меня сейчас затык капитальный! есть мега2560 и долбанный рампс1.4 да и еще экран с энкодером и кнопкой на гем. вчера пол дня убил так и не понял почему не смог кнопки поднять. Две кнопочки всего !  то что показал тестер- выносит напроч мозг.  

 А имея подобный скеч, только для всех пинов- включил бы монитор потыкал кнопки и сразу видно на каких портах кнопа висит.

maxvalin
Offline
Зарегистрирован: 22.02.2016

когда куча периферии и нет инфы пинаутов короче. ну я бы например для этого использовал.

axill
Offline
Зарегистрирован: 05.09.2011

Если что то не так со схематикой то первое чем стоит заняться так это взять в руки мультиметр и все прозвонить

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

Immortal
Offline
Зарегистрирован: 28.12.2013

axill пишет:

Подход к написанию импонирует, но поясните для чего этот скетч? Для каких задач или ситуаций

особенно потпроверке астроенных систем таких как прерывания. Ищем контроллеры изготовленные кустарным способом?

Если что то не так со схематикой то первое чем стоит заняться так это взять в руки мультиметр и все прозвонить

Я собираю кастомные платы на ATmega128A с нужной мне обвязкой, сейчас вот из китая должна приехать очередная партия плат новой ревизии.

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

Сейчас я пользуюсь автоматическими тестами ArduinoUnit и конкретно этим digital_pin_test.ino

а в случае проблем - мультиметром и тестами выложенными в этой теме.

 

axill
Offline
Зарегистрирован: 05.09.2011

понятно. я все же начинаю с мультиметра и только потом нагружаю МК. при КЗ на шину питания например ваш скетч может только констатировать смерть, но не предотвратить

но это ваш метод, допускаю, что он в каком то виде применим и другими

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

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

Раз вы заказываете на заводе то там можно заказать и электротестирование, конечно за доп цену

Immortal
Offline
Зарегистрирован: 28.12.2013

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

КЗ на шину питания тут на 99% исключен, электротест его найдет, а САПР для разводки плат такого не допустит. В крайнем случае сработает самовосстанавливающийся предохранитель в БП.

Для проверки дорог к другим микросхемам пишется специфичный для каждой платы тест, так что тут тоже все тестируется.

Подобный тестовый код пишет любой разработчик плат на мк, просто не все им делятся. Цель этой темы в обмене идеями и универсальным кодом тестов.

АндрейS
Offline
Зарегистрирован: 13.04.2018

Приветствую! Подскажите пожалуйста, можно ли проверить этими скечтами ардуино DUE и как?