Basic idea of color look up table
Your problem here is you're working in bytes, but the framebuffer is conceptually in nibbles.

Say you have a screen 256x200, so you have a framebuffer of 256x200 nibbles, of 256x200/2 bytes.  That is fine, and what you have.

You then need to translate your X/Y coordinates into a framebuffer byte location.  For that you need to work with half the width, or half the height.  For example, the location 10,20 would equate to half the value of 20 widths + 10 bytes.  That would be (20 * 256 + 10) / 2 = 1285.

Now, you're half way there.  You know where in the framebuffer your chosen pixel is, but not which half of the byte.  For that you need to look at the full pixel location and see if it's odd or even.  20 * 156 + 10 = 2570.  That is an even number (2570 &amp; 1 = 0; the LSB is set to 0, so is even), so you want to only modify the lowest nibble of the value (if it were odd you'd modify the highest nibble - of course you could store them the other way around - see later).

So you would read the current value from the array, mask out the nibble you want to modify it so it's all 0, then overlay the new value.

Say the byte currently contains 0b10011100, you would AND it with 0b11110000 to result in 0b10010000.  Then you OR that result with your new pixel value, say 2, to result in 0b10010010.

If you were modifying the upper nibble you would first need to shift your colour value 4 bits left to make it 0b00100000 instead of 0b00000010, then or it with the masked out upper nibble of the byte.

Then you write the byte back again.

Now, displaying the framebuffer to the screen is a similarly onerous task:

You need to take each byte of the framebuffer and split it into two nibbles.  Right-shift the upper nibble 4 bits to make it a number between 0 and 15.  Look up the colour for the lower nibble, and place it on the screen.  Then do the same with the upper nibble placing in on the screen in the next pixel.  Then you advance to the pixel following that, so you have moved on 2 pixels in total.

Note from earlier - if you stored the even in the upper nibble and the odd in the lower nibble you'd just output the pixels in the opposite order - upper then lower.

Clear as mud now?