Having issues using an Arduino to emulate a shift register. Details inside.

Hello everyone,

Sorry about the title, that it’s not clearer. I’m not really sure how to phrase my issues so clearly in such a short title. Hopefully I can explain it better here.

I’m trying to use the Arduino to emulate a shift register chip. It seems to work, but then it doesn’t. What I’m trying to do is mimic a S88. The shift register is controlled down the line by a controller, a Marklin CS2.

First, a couple of links.

S88 - Principle and Problems ← This is some basic information on the principles of the s88 and the shift register.

http://usuaris.tinet.cat/fmco/images/s88_sch.gif ← This is a schematic of an s88. There are two shift registers, and 4 other chips which capture input. I only really need to utilize 3 of the 6 lines. Data Out, Clock, and Load. The reset is used to reset the latches on the chips that capture the input.

The basics here is that I’m trying to emulate the 4014N chip in that schematic, which is a shift register chip.

Now, there are two people I’ve found that tried to do this.

First: http://forum.arduino.cc/index.php?topic=226538.msg1639859#msg1639859
Second: S88NAVR/S88ArduinoProMini.ino at master · dirkjankrijnders/S88NAVR · GitHub

We will refer to them as GuyA, and GuyB.

I’m using the code from GuyA. I think the issue I’m having is similar to what he had? But it’s not been solved, from what I can tell. I stripped the code down to the basics and adjusted it so it only sends out two bits. 01

The problem is that at some point it starts sending out 101. An extra bit gets added to the front, which is the same value as the last bit. I’m not exactly sure how it’s getting shifted around. This makes more sense with a longer string.

So, on an 8bit string, normally it’d send something like 00100101, but when it sends the incorrect bits, it sends it as 100100101, so an extra bit is added. If the string was 00100100, then the incorrect string would be 000100100. If the correct string was 10100100, the incorrect string would be 010100100. And so forth.

I don’t know if this is an issue with the software, or a hardware issue. The code seems to function fine. Maybe it can’t keep up with the controller? It’s not a purely random thing though, It will go, say, 20 seconds sending the correct bits, but then it’ll go 20 seconds sending the incorrect bits. I’ve not timed it to know if it’s that consistent. The point is, it’s not a one off send, it sends it several times in a row with the bits shifted incorrectly, but at some point starts sending the correct bits again.

I can manipulate the bits it sends. Turning one of them on and off with a switch. That works fine, it doesn’t seem to have issues other than the bits getting shifted over.

I’ve looked at the code from GuyB. I think GuyA’s code is based off of his, but simplified greatly. I didn’t understand GuyB’s code until I saw GuyA’s code. I’ve not been able to try GuyB’s code yet, so I’m not sure if it’d have the same issue.

Maybe the Arduino isn’t fast enough to keep up with the controller? With how GuyA programmed it. GuyB uses a different method to communicate with the pins, but I don’t really understand how that is all setup yet. I’ve not got a chance to read into it beyond a few lines.

I’ve tried to put in some code to output some figures to the serial monitor, but everything seems okay. Maybe I’m looking at the wrong part of the program to know? I just output one of the values of the S88data array, and it shows the correct value, even when the controller (The CS2), shows the data shifted. So it makes me think that there is an issue with the communication from the Arduino to the CS2, like the timing gets off? Or something. I don’t know.

Maybe the Arduino isn’t fast enough to keep up with the controller?

How fast is the incoming data?

How about you post the actual code you are using, or is it the same as GuyA’s?

I haven’t analysed it yet but that code does not look too clever to me, there is a HUGE amount of <<'s involved and an ISR is not the fastest way to do stuff either.


Rob

For now I've been using GuyA's code. I just stripped out the extra registers to see if it was an overhead problem... too much data having to be processed? It didn't seem to affect it.

I found another post of his elsewhere and realized he's using an ESU controller, where mine is a Marklin. I'm not sure if that really makes such a difference, or why it would.

I'm not sure what the speed is that it's all functioning at. It seems weird in the way that it malfunctions. If the Arduino couldn't communicate fast enough, I'd have expected the results to be chaotic? I don't know. I don't really have the tools to analyze what's going on behind the scenes. I thought about seeing if there's a sketch for Arduino to make it a logic analyzer, and maybe that'd help give me a little insight.

The code is simple enough, and being the noob that I am, that's good. I've got my head wrapped around most(part?) of what's happening. I've been thinking about reading up on how to directly manipulate the pins so I can pump the data out faster. I don't know if that'd solve the problem though. I've read there's some overhead with using digitalWrite as opposed to direct manipulation.

I don't know, maybe I'm in over my head here. Even with understanding parts of the code, there's other aspects I don't fully understand. Because of that I don't really know how to break the problem down.

http://www.digital-bahn.de/info_tech/s88.htm

Here's another link, perhaps it is useful in some manner. A lot of the information I've come across isn't in english, so I've been using google translate to try and sort through it.

I thought about seeing if there's a sketch for Arduino to make it a logic analyzer, and maybe that'd help give me a little insight.

I believe there are such sketches, they won't be very fast I think but it would be worth having a look.

A logic analyser is the most useful tool you can have for embedded work, hands down. You can get a Saleae Logic 8 for $149 (less for the new 4-channel one) or a clone of it for about $20. I prefer to support the Saleae guys, but if you don't have the cash you can get the clone and still use the Saleae software.

directly manipulate the pins so I can pump the data out faster. I don't know if that'd solve the problem though. I've read there's some overhead with using digitalWrite as opposed to direct manipulation.

The code is already using direct manipulation, so in that respect there is nothing to be gained. Yes the code is simple but also quite inefficient I think. Interrupts are not the fastest way to do this and all those shift operations will be slow. There must be a better way but I haven't thought of it yet.


Rob

Just thinking off the top of my head here, this code should be a lot faster, it only implements the shift reg part not LOAD which AFAICT did nothing yet anyway as there was no code to output to the parallel pins. With no outputs to the parallel pins how are you testing this?

// S88 pins setup
#define S88DATAIN 5
#define S88DATAOUT 4
#define S88CLOCK 2
#define S88LOAD 3

#define N_REGS	3
#define N_BITS 	(N_REGS * 8)

uint16_t S88DataOutShiftRegister[N_BITS];
int 	rd_index = 0;
int 	wr_index = 0;

void setup() {
  attachInterrupt(0, CLOCK, CHANGE); // Interrupt stuff for the CLOCK and LOAD
  attachInterrupt(1, LOAD, RISING);
  pinMode(S88DATAOUT, OUTPUT);
  
  for (int i = 0; i < N_BITS; i++) {
	S88DataOutShiftRegister[i] = 0;
  }
  
}

void loop() { // No loop stuff because it's all interrupt driven.
}

void CLOCK() {

	byte dataBit 	= (PIND >> S88DATAIN) && 1;
	byte clockBit 	= (PIND >> S88CLOCK)  && 1;
	
	if (clockBit) {   // If rising edge, write top FIFO bit to S88DATAOUT
		if (S88DataOutShiftRegister[rd_index++])
			PORTD &= ~(1 << S88DATAOUT);
		else {
			PORTD |= (1 << S88DATAOUT);
		}
		rd_index = rd_index < N_BITS ? rd_index : 0;
		
	} else {   // If falling edge, read S88DATAIN -> Put the data into the FIFO
		S88DataOutShiftRegister[wr_index++] = dataBit;
		wr_index = wr_index < N_BITS ? wr_index : 0;
	}
}

void LOAD() // Setup the S88data arrays / shift registers... Now it's ready to be send!
{
}

I’m pretty sure it will be faster to represent the bits in a byte array, that way there is no shifting of them every time you get a new bit. And my making that array a FIFO there is nothing to do but update the read and write index variables.

I’m sure there is still much room for improvement, this is just a first pass.


Rob

Hey Rob,

I greatly appreciate that you’re taking the time to help me, especially with some thoughts on the code. As I understand his code better, I’ve started to think too that it might be more complicated than needed. I’m not as skilled a programmer though to know how to simplify it so easily. I did try some, but wasn’t met with complete success.

This morning I put together some photos to show you to help you understand the setup and what’s going on. After I read your reply last night, I did some further test and made some interesting observations. The problems I have with his code, they seem inconsistent in how they malfunction, and I’m not sure why that is. I do change things around a lot as I go though, so that’s likely a cause.

So, firstly some images, and then I’ll give some thoughts.

This is the setup I have. The CS2 is the controller, up in the right you can see a real S88. It connects via a ribbon cable. Below I have my Arduin which I’ve connected with jumper cables.

This is one of the switches. It’s directional and has two outputs.


They don’t have documentation that explains these settings, but I think they relate to the clock and load. I’d venture to guess that the interval is the clock intervals and that the query is the load intervals.


This shows what I see on the screen. With his code it’ll switch back and forth between the first and the second, so the bits get shifted over. They’re being shifted to the right.

Okay, so that’s the images.

Changing the S88 Interval and S88 Interval Query settings affects it. I had problems with it crashing when I used faster values. That was with the Arduino attached, with a real S88 it doesn’t cause such issues. I’ve also had issues where it causes the system to slow down, or hang. I’m not sure why though. If I select slower values, it seems to work better.

I did get his code working, but I couldn’t do it with 10 shift registers like he had, I had to cut it down to only 2 and it’d start working then. If there was any more than that, it’d start shifting one over, back and forth. It’s weird, it’s behaving differently than it did the other day. The other day the shift was slow, it’d be 10-20 seconds between the shifts. Also, it did it regardless if I had 10 shift registers or just one. Last night, it’d do it immediately. Maybe that’s why it was causing it to crash? It couldn’t handle having so many inputs change so quickly at the same time? I don’t know. At faster settings, it’ll shift one bit over, at slower settings it seems to work like it should.

I wish I could give a better explanation. I kind of threw this information together in a rush as I was getting ready for work.

The S88DATAIN isn’t being utilized. I don’t know if it needs to be. For completeness sake, I guess one would want to implement it. The Data out of a real S88 would connect into the S88DATAIN on the Arduino. Or, another Arduino could be connected.

S88DATAOUT is sending the data to the CS2. The CS2 controls the S88Clock and S88LOAD.

I have to read through it again, so I’m not sure if I’m correct in this statement. I believe what’s happening is that a signal gets sent over S88LOAD, which causes the 4014N Shift Register chip to load in the data that’s being stored in the 4044N chips. At some point here, after it’s loaded, it sends a signal down the Reset line that causes the 4044N chips to reset and wait for new input. The Data is shifted down the line towards the controller, the CS2 in this case. And after that, it starts all over again.

So in GuyA’s code, in the Load function, it’s loading the data into the shiftregisters. On the Clock function, it’s shifting it down. The LOAD Function will get called once, at the start, and then the Clock function will get called until all the data has been loaded in. I’m guessing the Clock function will trigger 64 times (the limit to the amount of modules that the CS2 supports), before it triggers the load signal again.

I believe on the real S88, when it sends data to the CS2, it’s only sending 8 bits at a time. Makes sense. There’s two shift register chips in the S88, but the data from one chip is being sent to the CS2, while the data from the other chip is being loaded into the first chip, so it can be sent down the line. In GuyA’s code, he’s sending 16 bits with each shift.

Thanks again for the help. I’m trying hard to wrap my head around everything.

Someone made a sketch for an Arduino that can pull in input from an S88. I’d venture to say you don’t have the hardware I do (The CS2, or other similar device), but if you’re curious to see if your code works, you could do it with two Arduinos. The railunio library has the ability to interface with the S88 modules. Below is a link to the code, and a link to Desktop Station, a program you could use to monitor the inputs. They interface with Marklin’s system via Can-Bus, but that’s not needed for the S88 connection.

In this setup, you’d have an Arduino with Railunio acting as the controller, in place of a CS2 (Like I have). On a second Arduino, you could load in GuyA’s code and see what happens.

https://code.google.com/p/railuino/
http://yaasan.mints.ne.jp/index.html
http://yaasan.mints.ne.jp/ready.html#S88 ← the information for connecting the S88.

I understand you’re helping me out of kindness, and if you’re anything like me, you’re wall to wall busy as it is. So, because of that, I don’t expect you to go through the trouble of dealing with setting up a couple of Arduinos to help work out some of the code. I provide that information for information’s sake. The thoughts you’ve provided and your first snippet of code has provided me a lot to think about and has helped my understanding greatly. I think my greatest limitation right now is my limited programming knowledge.

Just a FYI, in case you’re curious. The reason I’m doing this is a two part problem. The first is that it’s difficult to find S88 modules in the states. They’re usually pretty expensive too, more so than I think they should be considering how basic they are. The second is that I want to build a wireless system up around it so I don’t have to run cables all over the place.

The added benefit is that I can write conditional state information into it, so I can have more complex triggers than I’m afforded with using the standard system. I could, in theory, handle that part through the use of a computer and software that is freely available, but I’m also very keen on not having to connect to a computer. It’s all about having as compact and contained of a system as I can get. It’s also about reducing the wires to as few as I can get away with.

Thanks, that gives me a better idea of what’s going on.

Looking at the 4014 data sheet I’m not convinced that code is right, presumably it does work but everything is done on the clock’s rising edge not on the load edge.

Anyway I’ve done a new version.

// S88 pins setup
#define S88DATAIN 5
#define S88DATAOUT 4
#define S88CLOCK 2
#define S88LOAD 3

#define N_REGS	2
#define N_BITS 	(N_REGS * 8)

byte 	S88DataOutShiftRegister[N_BITS];
int 	rd_index = 0;
int 	wr_index = 0;

// S88 test data, when this works completely I want to add the wireless stuff to manipulate this data array.
uint8_t S88data[N_BITS] = { 	
	0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
	}; 

void setup() {
  attachInterrupt(0, CLOCK, RISING); // Interrupt stuff for the CLOCK
  pinMode(S88DATAOUT, OUTPUT);
}

void loop() { // No loop stuff because it's all interrupt driven.
}

void CLOCK() {

	byte dataInBit 	= (PIND >> S88DATAIN) && 1;
	byte loadBit 	= (PIND >> S88LOAD)  && 1;
	
	if (loadBit) {   	// LOAD (PE pin on 4014) is asserted 
		// put the test data into the FIFO
		for (int i = 0; i < N_BITS; i++) {
			S88DataOutShiftRegister[i] = S88data[i];
		}	
		rd_index = 0;
		wr_index = 0;		
	} else { 			// LOAD is not asserted
		// Get bit from upstream unit and add to FIFO
		S88DataOutShiftRegister[wr_index++] = dataInBit;
		wr_index = wr_index < N_BITS ? wr_index : 0;
	}

	// setup data out so it's at the right level for the downstream unit when the next clock occurs
	if (S88DataOutShiftRegister[rd_index++])
		PORTD |= (1 << S88DATAOUT);
	else 
		PORTD &= ~(1 << S88DATAOUT);
	
	rd_index = rd_index < N_BITS ? rd_index : 0;		

}

As you say I don’t have that gear so can’t test it, I can’t really set up two Arduinos (or indeed any hardware) right now either as I’m in the process of building my workshop and everything is in total disarray.

Anyway you don’t have to go this way of course, you may feel more comfortable with the more inline approach used by GuyA’s code, but it’s worth plugging this in to see what happens.


Rob

Hey,

Thanks for the code snippets. I'll play with it once I get home. GuyA's approach does seem a little clunky in some regards, so the code you've provided, I think it'll provide a better base. I got his code to work, but as I said before, there appears to be problems with it. I might have some follow up questions when I get into the thick of it.

And no worries. Disarray is understood.

Just wanted to give you an update. I plugged your code in. It's sending data out now, but something is off as it's not stable, the data it sends out. A timing issue? Or something. Not surprising considering you're stabbing in the dark since you've not got the hardware to interface it to like I do.

I think I can get it working though. I'm at least 45% confident I can. I think I'll pull the code apart and break it down to as simple of a setup as I can get it. So it just sends out a string of predefined-bits, and does nothing else. Then from there I can build up the rest of the functions it needs.

Hey Rob, I hope you’re still out there. I’ve been a bit busy with work, and so I’ve only really just now got to sorting some of this out. I’ve got an update for you on all of this. I ordered a logic analyzer like you suggested and this turned out to be the key to everything. I hadn’t imagined so. I wasn’t sure if it’d actually help, if it’d actually tell me what I needed to know, but it did that and more.

So, I realized all my problems with running Guy A’s code was because I hadn’t connected ground from the controller to the Arduino. Sooo… yeah. I realized this when I connected the logic analyzer for the first time and got some weird readings. I opened up the manual and saw a note about connecting to ground. Makes sense. Things worked then. I don’t want to use Guy A’s code though, and this is something you helped me realize. It can be done better. It can be done very simple.

A very important mistake to have made (Not connecting ground) though because it led me to here, and a much better understanding of all of this.

A screenshot of the logic analyzer.

I learned a couple of important things to this. Firstly, it’s not important to have the data in sets of 8/16, or whatever. It doesn’t need to mimic that aspect of the S88. That’s something that is messy with GuyA’s code. It’s just not needed.

With each clock cycle one bit is sent. It’s either high for on or low for off. You can see this in the screenshot. The Load signal is sent to load the data so it’ll be ready to send to the controller. Then the clock signal starts. With each tick of the clock signal, a bit is sent in.

So it should work that the code loads whatever data it has gathered into a variable and then waits for the start of the clock signal. When the clock signal starts, with each tick, it should send the first bit in line in the variable and it should also pull a bit from the incoming line (From a connected S88 down the line) and add it to the tail end of the variable.

Rob, it’s been your help and talking with you that has helped me to understand this and see how simple it actually is.

A very important mistake to have made (Not connecting ground)

Arguably the most common problem we have here, why we didn't ask about this I have no idea.

Looks like it's working now.

I reckon we should distribute a logic analyser to all forum members, it would cut the number of questions in half :slight_smile:


Rob

Hi,

I see you have the same problem as me (GuyA :slight_smile: ). I already started again to find it out what the problem is after a short break.
Have you optimized my code? Can you post it then in this topic?

Cheers,
Dylan

@Graynomad
I tried your code but it the same problem that I have when I try to use SPI slave mode to simulate a S88. The shift registers aren’t shifted so the command station repeats the first 8bits on every S88 module. It should be only on 1 S88 module of course.

Cheers,
Dylan/GuyA