Help with AR49-M25S absolute encoder and RS485

Hey all, I’ve been banging my head against this for awhile now and I’ve gotten to the point where I need assistance from more experienced developers.

I’m currently using an MKS XDrive Mini, a MAX485, and an AR49-M25S using RS485 for communication. Here’s what I have so far:

#include <SimpleFOC.h>

#define RS485_RO PA1
#define RS485_RE PA2
#define RS485_DE PA3
#define RS485_DI PA0

#define AR49_READ     0x02
#define AR49_ZERO_RST 0xC2


HardwareSerial Serial4(RS485_RO, RS485_DI);

char buffer[10];

void PrintBits(char c)
{
  for(int i = 7; i >= 0; i--)
  {
    Serial.print(bitRead(c,i));
  }
}

float OnReadEncoder()
{
  digitalWrite(RS485_RE, HIGH);
  digitalWrite(RS485_DE, HIGH);
  delayMicroseconds(2);

  Serial4.write(AR49_READ);

  Serial4.flush();
  delayMicroseconds(5);

  digitalWrite(RS485_RE, LOW);
  digitalWrite(RS485_DE, LOW);

  delayMicroseconds(20);

  Serial.print("Response from encoder:");

  int bytesReceived = Serial4.available();
  if (bytesReceived > 0)
  {
    Serial4.readBytes(buffer, bytesReceived);

    for (int i = 0; i < bytesReceived; i++)
    {
      Serial.print(' ');
      PrintBits(buffer[i]);

      if (buffer[i] == AR49_READ)
      {
        Serial.print(" (Read cofirmed!) ");
      }
    }
  }

  Serial.println("");

  return 0;
}

void OnInitEncoder()
{

}

GenericSensor encoder = GenericSensor(OnReadEncoder, OnInitEncoder);

void setup()
{
  pinMode(RS485_RE, OUTPUT);
  pinMode(RS485_DE, OUTPUT);

  Serial4.begin(2500000, SERIAL_8N1);

  encoder.init();

  Serial.begin(115200);

  delay(1000);
}

void loop()
{
  encoder.update();
  
  delay(1000);
}

Unfortunately what I’m getting back from the encoder doesn’t seem to make any sense nor conform to what I should expect to be getting back. Here’s the documentation for the encoder https://docs.broadcom.com/doc/AR49-Series-AN starts on Page 39.

Here’s a sample of what I’m getting back:

Response from encoder: 00010000 01101111 11111110
Response from encoder: 00110000 10111111 11111011 10011100
Response from encoder: 00110000 11111000 11111011 11111111
Response from encoder: 00110000 11100000 11111011 11110111
Response from encoder: 00010000 01101111 11111110
Response from encoder: 00010000 11100011 11111011 11110110
Response from encoder: 00110000 11100110 11111011 11110011
Response from encoder: 00110000 11100111 11111011 11110000

Any ideas or suggestions would be greatly appreciated.

I’ve adjusted some of the timings and removed the Serial4.flush() and am now getting consistent values in the first two bytes but they still don’t make any sense to me. According to the documentation the first byte should be the requested command, which in this case should be 0x02. Here’s what I’m getting now.

Response from encoder: 10000011 10000000 01111111 11111011
                             83        80        7F        FB
Response from encoder: 10000011 10000000 11111111 01111111 00111110 11111111
                             83        80        FF        7F        3E        FF
Response from encoder: 10000011 10000000 01111111 11111111
                             83        80        7F        FF
Response from encoder: 10000011 10000000 11111111 01111111 11111110 11111110
                             83        80        FF        7F        FE        FE
Response from encoder: 10000011 10000000 01111111 11111110
                             83        80        7F        FE
Response from encoder: 10000011 10000000 01111111 11111000
                             83        80        7F        F8
Response from encoder: 10000011 10000000 11111111 01111111 11111110 11111111
                             83        80        FF        7F        FE        FF
Response from encoder: 10000011 10000000 11111011 01111111 11111110 11111110
                             83        80        FB        7F        FE        FE

Still chipping away at this. I purchased a logic analyzer so I could verify the signals going back and forth and captured this.

So it seems I’m sending the correct byte 0x02, and the encoder is acknowledging the request along with sending the expect response. At this point I’m trying to figure out why I’m unable to read back the response from the Serial4 object.

With the help of a friend I managed to get this working. The main issue was the 2.5Mbps baud rate. It seems UART4 (PA0, PA1) cannot reliably receive at that speed. Switching to USART2 (PA1, PA2) made it possible to read the encoders response. For good measure I also added a SystemClock_config to match what the original firmware had setup.

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
    Error_Handler();
  }

    /**Configure the Systick interrupt time 
  */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}

Hopefully that helps others who might run into the same issue.