Magnetic sensor reading and binary bit masking

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all! I'm trying to read data from AS5040 Magnetic sensor (see datasheet of chip here and for the adapter board I'm using here) using the SPI output mode, with my ATmega4809 Curiosity Nano board. 
In SPI output mode, pins used are CSn, CLK, and DO. CSn and CLK pins are configured as outputs, while DO is configured as input.

 

The DO pin outputs a 16-bit data (in binary), with the first 10bits as the angle info, and the last 6 bits as the status info. (I disregarded the status reading for now but it is all pre-set to "OK" in Arduino since it's more of a hardware setting).

To get the position info, I predefined an anglemask of 1111111111000000 then mask it with the first 10 bits in the packeddata, put it in angle, then shift the other 6 bits to get 10 bits.
The output deg is the decimal value of angle multiplied by 0.3515625 (from 360/1024 resolution). I'm trying to printf the output deg but no value comes out.

 

To give an example:

packeddata:   00001010 11110000   (16 bits)

anglemask:    11111111 11000000   (16 bits)

angle:            00001010 11000000   (16 bits)

angleshift:      00001010 11              (10 bits)

DEC(angleshift)     43 (x0.3515625)

Degrees:              15.1145 degrees

 

The code is below. I got it working under Arduino UNO since I'm quite familiar with it.

 

Code for sensor.h

#include <avr/io.h>
#include <avr/delay.h>

#define SENSOR_CLK_PORT		PORTA
#define SENSOR_CS_PORT		PORTA
#define SENSOR_DATA_PORT	PORTA

#define SENSOR_CLK_PIN		0	//A0
#define SENSOR_CS_PIN		1	//A1
#define SENSOR_DATA_PIN		2	//A2

Code for sensor.c

#include "sensor.h"
#define _BV(bit) (1<<(bit))

void sensor_setup()
{
  SENSOR_CLK_PORT.DIR |= _BV(SENSOR_CLK_PIN);		/* CLK as OUTPUT */
  SENSOR_CS_PORT.DIR |= _BV(SENSOR_CS_PIN);	        /* CSn as OUTPUT */
  SENSOR_DATA_PORT.DIR &= ~_BV(SENSOR_DATA_PIN);	/* DO as INPUT */
}

Code for main.c

#include <avr/io.h>
#include <stdio.h>
#include "sensor.c"
#include "uart.c"

#define _BV(bit) (1<<(bit))

uint16_t inputstream = 0;				/* 1-bit read from pin */
long packeddata = 0;					/* 2 bytes concatenated from inputstream */
long angle = 0;						/* Holds processed angle value */
long anglemask = 1111111111000000;			/* 0b1111111111000000: mask to obtain first 10 digits containing the position info */
float deg = 0;						/* Final angle, with x0.3515625 */
char str[10];

int uart_putchar(char str, FILE *stream);
FILE myline = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_RW);

int main(void)
{
  uart_init();
  stdout = &myline;

  sensor_setup();
  while(1)
  {
    SENSOR_CS_PORT.OUT |= _BV(SENSOR_CS_PIN);				* CSn pin HIGH */
    SENSOR_CLK_PORT.OUT |= _BV(SENSOR_CLK_PIN);				/* CLK pin HIGH) */
    _delay_ms(10);							/* Time between readings */
    SENSOR_CS_PORT.OUT &= ~_BV(SENSOR_CS_PIN);				/* CSn pin LOW */
    _delay_us(100);							/* Chip initialization delay */
    SENSOR_CLK_PORT.OUT &= ~_BV(SENSOR_CLK_PIN);			/* CLK pin LOW */
    _delay_us(100);

    for (uint8_t i = 0; i < 16; i++)					/* Clock signal, 16 transitions */
    {
      SENSOR_CLK_PORT.OUT |= _BV(SENSOR_CLK_PIN);			/* Clock goes HIGH */
      _delay_us(100);
      inputstream = (SENSOR_DATA_PORT.IN & _BV(SENSOR_DATA_PIN));	/* Read 1 bit of data from pin */
      packeddata = ((packeddata << 1) + inputstream);			/* Left-shift summing variable */
      SENSOR_CLK_PORT.OUT &= _BV(SENSOR_CLK_PIN);
      _delay_us(100);
    }
    angle = packeddata & anglemask;
    angle = (angle >> 6);
    deg = angle * 0.3515625;
    itoa(deg,*str,10);
    printf("Degrees: ");
    printf("%s\n",str);
    _delay_ms(1000);

    packeddata = 0;
    angle = 0;
  }
}

Note: I just used uart.c to be able to use printf.

 

My problems are:
1. Does the packeddata contains binary?
2. Am I right to mask packeddata and anglemask by "angle = packeddata & anglemask"?
3. There is no read output from deg, so also no output in str. Am I using the itoa right?

 

Any insight on the code is much appreciated.

 

franco

This topic has a solution.

I'm new.

Last Edited: Thu. Jan 16, 2020 - 08:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For all practical purposes, ALL data is binary. And it is also hex. And it is also decimal. Only difference is how you interpret it.

 

Will leave the other question for other forum folks.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

try itoa( deg, &str[0], 10 );
You can also do printf( "Degrees: %s\n", str );

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 ka7ehk wrote:
For all practical purposes, ALL data is binary. And it is also hex. And it is also decimal. Only difference is how you interpret it.

Thanks for this! This helped me in understanding the data from the sensor!

 

mikech wrote:
You can also do printf( "Degrees: %s\n", str );

Thank you for this! It helped me lessen the lines in coding, and it's easier and direct.

 

For now, I knew what went wrong in my coding.

francoder wrote:

inputstream = (SENSOR_DATA_PORT.IN & _BV(SENSOR_DATA_PIN))

I must add an inputstream >> 2 after reading, to output a binary code of 16 bits. Before, it outputs ex: 0040 4400 4040 0000, now it outputs: 0010 1100 1010 0000.

 

franco

I'm new.

Last Edited: Thu. Jan 16, 2020 - 08:11 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

mikech wrote:
try itoa( deg, &str[0], 10 );
Why itoa()? If printf() is available and already being used why not simply %d  or, actually %f seems more appropriate for "float deg;". As it stands deg is being truncated to int by itoa() anyway. So...

    deg = angle * 0.3515625;
    itoa(deg,*str,10);
    printf("Degrees: ");
    printf("%s\n",str);

becomes:

    deg = angle * 0.3515625F;
    printf("Degrees: %f\n", deg);

and drop "char str[10]" all together.

 

(you may want to limit the format of %f to perhaps be more like %03.1f or something like that?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
(you may want to limit the format of %f to perhaps be more like %03.1f or something like that?)

Is there any possibility that my chip(Atmega4809)/software(AS7) does not support %f? Every time I use %f, it only outputs "?" but %d or %s works just fine. I can't print any float.

I'm new.

Last Edited: Thu. Jan 16, 2020 - 11:48 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Google found this:

 

https://startingelectronics.org/...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for this! It's all working now. Sorry for the trouble.

I'm new.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For the benefit of others who may read this thread, closer to home the actual manual for the compiler has this on the subject:

 

https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

 

which explains all about libprintf_flt.a and so on (see text "Since the full implementation..." onwards)

 

(actually that documentation is out of date - it also mentions the need for "-lm" but for a long time this has now been done automatically so is not a manual requirement any more).