{"id":354,"date":"2025-07-25T07:55:53","date_gmt":"2025-07-25T07:55:53","guid":{"rendered":"https:\/\/www.maddox.pro\/?p=354"},"modified":"2025-07-25T07:55:53","modified_gmt":"2025-07-25T07:55:53","slug":"finally-data-fun-with-transputers","status":"publish","type":"post","link":"https:\/\/www.maddox.pro\/?p=354","title":{"rendered":"Finally, data (Fun with Transputers)"},"content":{"rendered":"\n<p>I finally managed to get data into and out of the transputer module (TRAM).<\/p>\n\n\n\n<p>To do this I used an Arduino Micro I had (as it&#8217;s 5V) and some breadboard. Now the TRAM pulls 800mA at 5V and the breadboard struggles with this, so I ended up using 4 links for 0V and 4 links for 5V and pushing the power supply to 5.5V to get 5V on the TRAM (not a problem on a PCB).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"831\" src=\"https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-1024x831.jpg\" alt=\"Arduino micro, an Inmos TRAM and a whole bunch of wires.\n\" class=\"wp-image-355\" srcset=\"https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-1024x831.jpg 1024w, https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-300x244.jpg 300w, https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-768x624.jpg 768w, https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-1536x1247.jpg 1536w, https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-2048x1663.jpg 2048w, https:\/\/www.maddox.pro\/wp-content\/uploads\/2025\/07\/ArduinoTRAM-1140x926.jpg 1140w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>I added some LEDs to various signals just so I had some confirmation that it was actually doing something.<br>I also ran the transputer links at 10Mbps rather than 20 as I was concerned about signal integrity ono a broadboard (let&#8217;s be honest, they&#8217;re not great at the best of times).<\/p>\n\n\n\n<p>The next step is to try the same with QBASIC in DOS and see if that works, now I know what a correct behaviour is.<\/p>\n\n\n\n<p>Here is the output of the code;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RESETTING C011\nRESETTING TRAM\nRead memory location power up contents\nINPUT STATUS:0\nOUTPUT STATUS:1\nsend: 0x1\nsend: 0x0\nsend: 0xF0\nsend: 0x0\nsend: 0x80\nREAD: 0xFF\nREAD: 0xFF\nREAD: 0xFF\nREAD: 0xFF\nWrite new value\nsend: 0x0\nsend: 0x0\nsend: 0xF0\nsend: 0x0\nsend: 0x80\nsend: 0xAA\nsend: 0x55\nsend: 0xAA\nsend: 0x55\nsend: 0x1\nsend: 0x0\nsend: 0xF0\nsend: 0x0\nsend: 0x80\nREAD: 0xAA\nREAD: 0x55\nREAD: 0xAA\nREAD: 0x55\nINPUT STATUS:0\nOUTPUT STATUS:1<\/code><\/pre>\n\n\n\n<p>The transputer is little endian, which is why the address seems backwards, and yes the start of RAM is at 0x80000000, internal transputer ram is 0x80000000 to 0x80000FFF and external starts at 0x80001000 and goes up to whatever you have on the TRAM (1MByte, or 256K words in my case).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>So the code sends a read command (0x01) followed by the 32bit address.<\/li>\n\n\n\n<li>Then reads 4 bytes back<\/li>\n\n\n\n<li>Next it sends a write command (0x00) followed by the same 32bit address<\/li>\n\n\n\n<li>Then we send 4 bytes of data (0x55AA55AA)<\/li>\n\n\n\n<li>Then we send a read command again, address and four reads!<\/li>\n<\/ul>\n\n\n\n<p>My Arduino code is here;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/*\n  C011 test\n  *\/\n\n#define nCS 12      \/\/ D12 is nCS\n#define RnW 11      \/\/ D11 is R\/nW\n#define RS0 18      \/\/ D18 is RS0\n#define RS1 19      \/\/ D19 is RS1\n#define RST 15      \/\/ D15 is RESET (active HIGH)\n\n#define DB0 10      \/\/ D10 is data bus 0\n#define DB1 9       \/\/ D9 is data bus 1\n#define DB2 8       \/\/ D8 is data bus 2\n#define DB3 7       \/\/ D7 is DB3\n#define DB4 6       \/\/ D6 is D4\n#define DB5 5\n#define DB6 4\n#define DB7 3\n\n#define TRAM_RST 14        \/\/ D14 for TRAM reset (active HIGH)\n#define TRAM_ANALYSE 16    \/\/ D16 TRAM ANALYSE\n#define TRAM_nERROR 17     \/\/ D17 for TRAM nERROR\n\n\/\/ Send data to the C011\n\/\/   sets the pinmode to outputs, toggle CS and WR, set back to input\nvoid SendData(uint8_t data)\n{\n  pinMode(DB7, OUTPUT);\n  pinMode(DB6, OUTPUT);\n  pinMode(DB5, OUTPUT);\n  pinMode(DB4, OUTPUT);\n  pinMode(DB3, OUTPUT);\n  pinMode(DB2, OUTPUT);\n  pinMode(DB1, OUTPUT);\n  pinMode(DB0, OUTPUT);\n\n  digitalWrite(DB7, data &amp; 0x80);\n  digitalWrite(DB6, data &amp; 0x40);\n  digitalWrite(DB5, data &amp; 0x20);\n  digitalWrite(DB4, data &amp; 0x10);\n  digitalWrite(DB3, data &amp; 0x08);\n  digitalWrite(DB2, data &amp; 0x04);\n  digitalWrite(DB1, data &amp; 0x02);\n  digitalWrite(DB0, data &amp; 0x01);\n\n  delay(1);\n  digitalWrite(RnW, LOW);\n  delay(1);\n  digitalWrite(nCS, LOW);\n  delay(1);\n  digitalWrite(RnW, HIGH);\n  delay(1);\n  digitalWrite(nCS, HIGH);\n  delay(1);\n\n  pinMode(DB7, INPUT);\n  pinMode(DB6, INPUT);\n  pinMode(DB5, INPUT);\n  pinMode(DB4, INPUT);\n  pinMode(DB3, INPUT);\n  pinMode(DB2, INPUT);\n  pinMode(DB1, INPUT);\n  pinMode(DB0, INPUT);\n\n  delay(10);\n}\n\n\/\/ Read data from the C011\n\/\/   sets the pinmode to input, toggle CS and DR, leave pins as input\n\/\/   return read value\nuint8_t ReadData(void)\n{\n  uint8_t temp;\n  pinMode(DB7, INPUT);\n  pinMode(DB6, INPUT);\n  pinMode(DB5, INPUT);\n  pinMode(DB4, INPUT);\n  pinMode(DB3, INPUT);\n  pinMode(DB2, INPUT);\n  pinMode(DB1, INPUT);\n  pinMode(DB0, INPUT);\n\n  delay(1);\n  digitalWrite(RnW, HIGH);\n  delay(1);\n  digitalWrite(nCS, LOW);\n  delay(1);\n\n  temp = digitalRead(DB7);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB6);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB5);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB4);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB3);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB2);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB1);\n  temp &lt;&lt;= 1;\n  temp += digitalRead(DB0);\n\n\n  digitalWrite(RnW, HIGH);\n  delay(1);\n  digitalWrite(nCS, HIGH);\n  delay(1);\n  \n  delay(10);\n\n  return temp;\n}\n\n\nvoid ShowInputStatus(void)\n{\n  \/\/ read input status\n  digitalWrite(RS0,0);\n  digitalWrite(RS1,1);\n  uint8_t data = ReadData();\n  Serial.print(\"INPUT STATUS:\");\n  Serial.println(data);\n  delay(10);\n}\n\nvoid ShowOutputStatus(void)\n{\n  \/\/ read OUTPUT status\n  digitalWrite(RS0,1);\n  digitalWrite(RS1,1);\n  uint8_t data = ReadData();\n  Serial.print(\"OUTPUT STATUS:\");\n  Serial.println(data);\n  delay(10);\n}\n\n\nvoid WriteTRAMData(uint8_t data)\n{\n  \/\/ Write Data\n  Serial.print(\"send: 0x\"); Serial.println(data,HEX);\n  digitalWrite(RS0,1);\n  digitalWrite(RS1,0);\n  SendData(data);\n}\n\nuint8_t ReadTRAMData(void)\n{\n  \/\/ READ data\n  digitalWrite(RS0,0);\n  digitalWrite(RS1,0);\n  uint8_t data = ReadData();\n  Serial.print(\"READ: 0x\"); Serial.println(data, HEX);\n}\n\n\n\n\/\/*************************************************************************\n\/\/ the setup function runs once when you press reset or power the board\nvoid setup() \n{\n  Serial.begin(115200);\n  delay(500);\n\n  pinMode(LED_BUILTIN, OUTPUT);\n  digitalWrite(LED_BUILTIN, HIGH);\n\n  while(!Serial.available())      \/\/ wait for a character from serial, as the monitor doesn't load quick after programming and I Want to follow the progress\n  {\n    Serial.print(\"Waiting \");\n    delay(300);\n  };\n  Serial.println(\"\");\n\n  \/\/ data control setup\n  pinMode(nCS, OUTPUT);\n  digitalWrite(nCS, HIGH);\n  pinMode(RnW, OUTPUT);\n  digitalWrite(RnW, LOW);\n  pinMode(RST, OUTPUT);\n  digitalWrite(RST, LOW);\n\n  \/\/ Databus setup\n  pinMode(DB7, INPUT);\n  pinMode(DB6, INPUT);\n  pinMode(DB5, INPUT);\n  pinMode(DB4, INPUT);\n  pinMode(DB3, INPUT);\n  pinMode(DB2, INPUT);\n  pinMode(DB1, INPUT);\n  pinMode(DB0, INPUT);\n\n  \/\/ RS setup\n  pinMode(RS0, OUTPUT);\n  pinMode(RS1, OUTPUT);\n  digitalWrite(RS0, LOW);\n  digitalWrite(RS1, LOW);\n\n  \/\/ TRAM pins\n  pinMode(TRAM_ANALYSE, OUTPUT);\n  pinMode(TRAM_RST, OUTPUT);\n  pinMode(TRAM_nERROR, INPUT);\n\n  \/\/ init things\n  delay(100);\n  Serial.println(\"RESETTING C011\");\n  digitalWrite(RST, HIGH);\n  delay(10);\n  digitalWrite(RST, LOW);\n  delay(100);\n  \n  Serial.println(\"RESETTING TRAM\");\n  digitalWrite(TRAM_RST, HIGH);\n  delay(500);\n  digitalWrite(TRAM_ANALYSE, HIGH);\n  delay(500);\n  digitalWrite(TRAM_RST, LOW);\n  delay(500);\n  digitalWrite(TRAM_ANALYSE, LOW);\n  delay(500);\n\n  \/\/ Write input status   (disable interrupts)\n  digitalWrite(RS0,0);\n  digitalWrite(RS1,1);\n  SendData(0x00);\n  delay(10);\n\n  \/\/ Write OUTPUT status   (disable interrupts)\n  digitalWrite(RS0,1);\n  digitalWrite(RS1,1);\n  SendData(0x00);\n  delay(10);\n\n\n  delay(500);\n}\n\n\/\/ the loop function runs over and over again forever\nvoid loop() \n{\n  digitalWrite(LED_BUILTIN, HIGH);  \/\/ turn the LED on (HIGH is the voltage level)\n\n  Serial.println(\"Read memory location power up contents\");\n\n\/\/ read from address 0x8000F000  (Transputer external RAM)\n  ShowInputStatus();\n  ShowOutputStatus();   \n  WriteTRAMData(0x01);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0xF0);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0x80);\n  \n  delay(10);\n\n  ReadTRAMData();\n  ReadTRAMData();\n  ReadTRAMData();\n  ReadTRAMData();\n\n  delay(10);\n\n  Serial.println(\"Write new value\");\n\n\/\/ write a value to 0x80000F00\n  WriteTRAMData(0x00);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0xF0);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0x80);\n  WriteTRAMData(0xAA);\n  WriteTRAMData(0x55);\n  WriteTRAMData(0xAA);\n  WriteTRAMData(0x55);\n\n  delay(10);\n\n\/\/ read from address 0x8000F000  (Transputer external RAM)\n  WriteTRAMData(0x01);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0xF0);\n  WriteTRAMData(0x00);\n  WriteTRAMData(0x80);\n  delay(10);\n\n  ReadTRAMData();\n  ReadTRAMData();\n  ReadTRAMData();\n  ReadTRAMData();\n\n  ShowInputStatus();\n  ShowOutputStatus();   \n\n  Serial.println(\"done\");\n\n  digitalWrite(LED_BUILTIN, LOW);   \/\/ turn the LED off by making the voltage LOW\n\n\n  while(1)    \/\/ just a little loop so I know it's still alive.\n  {\n    Serial.print(\".\");\n    digitalWrite(LED_BUILTIN, LOW);   \/\/ turn the LED off by making the voltage LOW\n    delay(500);\n    Serial.print(\"o\");\n    digitalWrite(LED_BUILTIN, HIGH);   \/\/ turn the LED off by making the voltage LOW\n    delay(500);\n  };\n\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I finally managed to get data into and out of the transputer module (TRAM). To do this I used an Arduino Micro I had (as it&#8217;s 5V) and some breadboard. Now the TRAM pulls 800mA at 5V and the breadboard struggles with this, so I ended up using 4 links for 0V and 4 links for 5V and pushing the power supply to 5.5V to get 5V on the TRAM (not a problem on a PCB). I added some LEDs to various signals just so I had some confirmation that it was actually doing something.I also ran the transputer links at 10Mbps rather than 20 as I was concerned about signal integrity ono a broadboard (let&#8217;s be honest, they&#8217;re not great at the best of times). The next step is to try the same with QBASIC in DOS and see if that works, now I know what a correct behaviour is. Here is the output of the code; The transputer is little endian, which is why the address seems backwards, and yes the start of RAM is at 0x80000000, internal transputer ram is 0x80000000 to 0x80000FFF and external starts at 0x80001000 and goes up to whatever you have on the TRAM (1MByte, or 256K words in my case). My Arduino code is here;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[40],"tags":[],"class_list":["post-354","post","type-post","status-publish","format-standard","hentry","category-retro-computing"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/posts\/354","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=354"}],"version-history":[{"count":2,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/posts\/354\/revisions"}],"predecessor-version":[{"id":357,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=\/wp\/v2\/posts\/354\/revisions\/357"}],"wp:attachment":[{"href":"https:\/\/www.maddox.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=354"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.maddox.pro\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}