Project showcase
Nipkow Disk 32 Line Television

Nipkow Disk 32 Line Television © GPL3+

Arduino version of the early mechanical television, invented by Nipkow more than 100 years ago.

  • 5,327 views
  • 5 comments
  • 26 respects

Components and supplies

About this project

This project is a derivative of my "Nipkow Disk Based Digital Display Device" project.

Chall commented "Neat! If you can support 30x30, you could do images. Like they did back in the 30's".

So I wanted to see if this was possible with Arduino.

Code

Arduino codeArduino
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Arduino.h"
#include <SPI.h>
#include <SD.h>

// each frame contains 32x64 pixels ( 2048)
// each pixel is represented as one byte in a file on the SDcard. Only the lower 6 bits are used.
// running at 16 frames/s about 32K bytes/s has to be read from the SDcard.
// the SD card can easily do that on average, but some reads take much long than average.
// To overcome this problem two 256 byte buffers are used. When the device is streaming bytes from one buffer the other is being filled from SD card.

#define PinPulse               8  //  IR receiver circuit. (must be connected to  input capture pin 8 )
#define DAC_0LSB               2
#define DAC_1                  3 
#define DAC_2                  4
#define DAC_3                  5
#define DAC_4                  6
#define DAC_5                  7

#define SyncPixel              1005 // pixel number that should correspond with synchronisation pulse. Tune this to so that pixel0 corresponds with the upper left corner.
const byte NumberOfPixelBits   = 11;    //  2^NumberOfPixelBits pixels

// global variables used in interrupt routines
volatile unsigned int Pixel = 0x0700;    // current pixel index                  
volatile unsigned int lastT1capture, Period_Ticks; // used to calculate spinning frequency
volatile unsigned long NextOutputCompare32bit = 0;
volatile unsigned long PixelTime_16bitTickFraction = 1000000000;

volatile char SyncLow=0, SyncHigh =0;                                                                                                                                                                                     
File myFile;
uint8_t buffer[512];
int SubFrame = 0;
long Frame = 0;


void setup()
{
  pinMode(DAC_0LSB, OUTPUT);  
  pinMode(DAC_1, OUTPUT);    
  pinMode(DAC_2, OUTPUT);
  pinMode(DAC_3, OUTPUT);
  pinMode(DAC_4, OUTPUT);
  pinMode(DAC_5, OUTPUT);      
  pinMode(PinPulse, INPUT);  // Configure input capture pin on timer1
  digitalWrite(PinPulse,0);  // floating may have 50 Hz noise on it.
  if (!SD.begin(10)) {
     return;
  }
  myFile = SD.open("mov_26.bin");
  cli();                    //clear interrupts while configuring timer1
  TCCR1A = 0;               //TC1 Control Register A 
  TCCR1B = B01000011;       //TC1 Control Register B : free running 250kHz counter, noise canceller enabled, falling edge input capture
  TIMSK1 = B00100010;       //Timer/Counter 1 Interrupt Mask Register: Enable input capture Interupt (ICIE) , Enable Output Compare A Match Interrupt Enable (OCIEA)
  sei();                    // enable interrupts
}

// timer 1 capture interrupt: function is triggered each time the synchronisation hole passes the light sensor.
ISR (TIMER1_CAPT_vect)
{ 
  unsigned int T1capture = ICR1 ;                    // read timer1 value when the sync occured
  Period_Ticks =  T1capture - lastT1capture;  // period = time between new and previous sync
  if (Period_Ticks > 1000)                    // ignore very short periods
  {
    sei();                              // Increase max pixel clk by enabling nested interrupts (allows COMPA interrupt during sync interrupt)
    lastT1capture = T1capture ;
    signed int SyncError = Pixel - SyncPixel;      // We expect a certain pixel number when sync occurs. Calculate error.
    cli();                              // atomic update of outputcompareStep32bit
                                        // Calculate time between pixels = (time between syncs)/NumberOfPixels + correct part of the error. 
                                        // Expressed as 32bit value : 16 bit integer, 16bit fraction -> OutputCompareStep32bit
    PixelTime_16bitTickFraction  = ( ( long)Period_Ticks << (16 - NumberOfPixelBits) ) + ((signed long)SyncError << 6); // each sync a fraction of the error is corrected : 
  } 
}

// timer 1 output compare A interrupt :function is triggered each time a new pixel should be send to the led
ISR(TIMER1_COMPA_vect)
{ 
  PORTD = (PORTD & 0x03) | (((buffer[Pixel & 0x01FF]) & 0x3F)<<2); //  write 6 lower buffer values to 6 bit DAC outputs on port D
  OCR1A = (NextOutputCompare32bit >> 16);                          // set new output compare value ( = integer part of OutputCompareStep32bit )
  NextOutputCompare32bit += (PixelTime_16bitTickFraction);         // calculate new output compare value
   if ((Pixel & 0x01FF)==0x00) SyncHigh=1;                          //  trigger to load high bank from SDcard to buffer ( currently reading from low bank )
  if ((Pixel & 0x01FF)==0x0100) SyncLow=1;                         // trigger to load low bank from SDcard to buffer ( currently reading from high bank )
  Pixel++;                                                         // next pixel
  if (Pixel > ((1 << NumberOfPixelBits) - 1)) { Pixel = 0; } 
}


void loop() {
if (SyncLow)  { SyncLow=0;  myFile.read(buffer, 256); SubFrame++; }
if (SyncHigh) { SyncHigh=0; myFile.read(buffer+256, 256); SubFrame++;}
if (!myFile.available()) Frame=0;
if (SubFrame>7) { SubFrame=0; myFile.seek(2048*Frame); Frame++;}
}       
convert image folder to sdcard fileC#
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CreateFrames
{
    public partial class Form1 : Form
    {
        const string OutputFile  = "c:\\result\\mov_26.bin";
        const string InputFolder = "c:\\frames\\";  // images in folder must be 32x64 

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // open each frame in the inputfolder, gamma correct the image and blank left column. Write the image to the OutputFile in a binary format that can be read by Arduino
            BinaryWriter bw;
            bw = new BinaryWriter(new FileStream(OutputFile, FileMode.Create));                             
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(InputFolder);
            int Filecount = dir.GetFiles().Length;                     
            for (int N = 0; N < Filecount; N++)
            {
                string Name = InputFolder+"frame" + N.ToString()+".bmp";                                    
                pictureBox.Image = new Bitmap(Name);                           
                for (int rij = 0; rij < 32; rij++) for (int col = 0; col < 64; col++)
                    {
                        Color pix = ((Bitmap)pictureBox.Image).GetPixel(col, rij);
                        int val;
                        if (col == 0) val = 0; else val=pix.R;
                        Byte gammacorrected = (byte)Math.Round(63 * Math.Pow((double)val/255.0, 2.6));
                        bw.Write(gammacorrected);
                    }
                Application.DoEvents();
            }
                bw.Close();   
}
        }
    }
mov_26.zipArduino
The image file used in the movie ( unzip it before copying it to the sdcard)
The file is generated by the c# application (from a set of images). Arduino is reading the mov_26.bin file from sdcard and displays it on the disk
No preview (download only).

Schematics

schematics

Comments

Similar projects you might like

Nipkow Disk Based Digital Display Device

Project showcase by christopheArduino

  • 15,946 views
  • 8 comments
  • 51 respects

Arduino Amiga Floppy Disk Reader (V1)

Project tutorial by RobSmithDev

  • 14,688 views
  • 10 comments
  • 13 respects

Arduino Amiga Floppy Disk Reader/Writer (V2.2)

Project tutorial by RobSmithDev

  • 8,729 views
  • 21 comments
  • 14 respects

Use a hard disk like a rotational input device

Project tutorial by Arduino_Scuola

  • 3,307 views
  • 1 comment
  • 10 respects

Ultrasonic Ranging Using Arduino and Processing (Radar)

Project showcase by Bharath Rao M

  • 29,329 views
  • 15 comments
  • 50 respects

Wooden Chess Board with Piece Recognition

Project showcase by MaxChess

  • 28,975 views
  • 42 comments
  • 82 respects
Add projectSign up / Login