Read bit in ASM

Hi everybody,

I am using an ADC (MCP3208) 8-channel SPI . The problem is that the SPI.h library is too slow and I’m trying to make reading in ASM.

I can generate the signal CS (yellow), writing the ADC (blue) and the Clock (purple). But do not know how to read the 12-bit ADC data (green) from Clock 8 to 19 and store it in a var[n].

Thanks in advance.

The code I’m using is:

void setup(){
asm(“sbi 0x4, 0x5”); // CLOCK OUT
asm(“cbi 0x4, 0x4”); // DOUT IN
asm(“sbi 0x4, 0x3”); // DIN OUT
asm(“sbi 0x4, 0x2”); // CS OUT

asm(“sbi 0x5, 0x2”); // SET CS
}

void loop()
{
asm(“cbi 0x5, 0x2”); // CS
asm(“nop\n\t”“nop\n\t”“nop\n\t”“nop\n\t”“nop\n\t”);

asm(“sbi 0x5, 0x3”); // DIN UP
asm(“sbi 0x5, 0x5”); // CLOCK UP 1
asm(“cbi 0x5, 0x3”); //DIN DOWN
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 1

asm(“sbi 0x5, 0x3”); // DIN UP
asm(“sbi 0x5, 0x5”); // CLOCK UP 2
asm(“cbi 0x5, 0x3”); //DIN DOWN
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 2

asm(“sbi 0x5, 0x5”); // CLOCK UP 3
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 3

asm(“sbi 0x5, 0x5”); // CLOCK UP 4
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 4

asm(“sbi 0x5, 0x5”); // CLOCK UP 5
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 5

asm(“sbi 0x5, 0x5”); // CLOCK UP 6
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 6

asm(“sbi 0x5, 0x5”); // CLOCK UP 7
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 7

asm(“sbi 0x5, 0x5”); // CLOCK UP 8
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 8

asm(“sbi 0x5, 0x5”); // CLOCK UP 9
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 9

asm(“sbi 0x5, 0x5”); // CLOCK UP 10
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 10

asm(“sbi 0x5, 0x5”); // CLOCK UP 11
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 11

asm(“sbi 0x5, 0x5”); // CLOCK UP 12
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 12

asm(“sbi 0x5, 0x5”); // CLOCK UP 13
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 13

asm(“sbi 0x5, 0x5”); // CLOCK UP 14
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 14

asm(“sbi 0x5, 0x5”); // CLOCK UP 15
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 15

asm(“sbi 0x5, 0x5”); // CLOCK UP 16
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 16

asm(“sbi 0x5, 0x5”); // CLOCK UP 17
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 17

asm(“sbi 0x5, 0x5”); // CLOCK UP 18
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 18

asm(“sbi 0x5, 0x5”); // CLOCK UP 19
asm(“cbi 0x5, 0x5”); // CLOCK DOWN 19

asm(“sbi 0x5, 0x2”); // CS
asm(“nop\n\t”“nop\n\t”“nop\n\t”“nop\n\t”);

}

DS0007.png

Welcome,

Are you sure SPI is too slow? From google results, I can see many people using the same device with an arduino and the SPI library (or dedicated library for this device), with no problems. Maybe your problem is elsewhere then?

So if I read that well, in the setup you initialize the pins as input or output and have ChipSelect HIGH

then in you loop:

You set Chip Select to LOW to activate your ADC

You wait for 5 ticks (I assume a waiting period is required for analog-to-digital conversion and the master must wait for at least that period of time before issuing clock cycles. I assume you know that 5 ticks is good enough for your conversion to be done, I've not checked the spec for your ADC).

The you toggle 20 times bit 5 of PORTB between High/Low. PORTB maps to Arduino digital pins 8 to 13 so you are messing around with pin 13 which is indeed the SCK pin on a UNO

during the first 2 clock rise, you send a 1 on the MOSI pin

and then you just work your CLK pin up and down 18 times, creating a clock signal which runs as fast as possible - i.e. at 4 Mhz because sbi and cbi are 2 cycles instructions and your arduino probably runs at 16MHz.

That's sounds pretty good but you need to do things between the ups and down of your clock to read the data coming back from the ADC.

The theory says that during each SPI clock cycle, a full duplex data transmission occurs. The master sends a bit on the MOSI line and the slave reads it, while the slave sends a bit on the MISO line and the master reads it. This sequence is maintained even when only one-directional data transfer is intended.

So what you need to do now is select a register where you will store the incoming data. at each clock cycle you check the MISO pin status and store it somewhere. For your analog-to-digital converters will need to build a 12-bit word - so will need to combine 2 of the general working registers to get 16bit of storage space (Save on the heap the content of those registers before messing with them, restore after your function call) or another approach is to use DMA and store directly the result in the memory - where your variable will be read later. (you will need to pass that address to your function).

Now - that seems like a lot of hassle for getting fast, because adding the instructions to deal with the register or DMA will add also at least 8 more cycles to your code and you will drop below 1Mhz

the SPI Library takes advantage of the SPI hardware built into the micro controller so that you don't have to mess yourself with building the clock signal. IIRC the SPI library has a SPISettings object is used to configure the SPI port and you can pass the max speed of your ADC as first parameter and your Arduino will automatically use the best speed that is equal to or less than the number you use with SPISettings.

Are you 100% sure that this is too slow for your needs? at what frequency do you need to sample your analog signal??

8-bit Arduino inline assembly tutorial, port and pin manipulation, and SPI example code.

Using the SPI library and one specific one for this ADC (AH_MCP320x.c), the fastest read time (for 8 channels) is about 300us.

With a little hack in ASM, is 96us:

asm("cbi 0x5, 0x2"); // Clear pin B2 (D10)(CS) to 0
SPI.transfer((canal_0>>8 ) & 0xff); //send data
msb0 = SPI.transfer(canal_0 & 0xff) & B00001111; //receiving data
lsb0 = SPI.transfer(0x00);
asm("sbi 0x5, 0x2"); // Sets pin B2 (D10)(CS) to 1

But still there is a lot of time doing nothing. I think it can be faster. I just have to read a pin of PORTB (between UP and DOWN clocks) and transfer it to a 12 bits variable.

I don't know if I can explain what I want. I apologize for my English :frowning:

Cheers!!!