Hi,
Ive been trying to get my arduino uno rev4 MINIMA to act as an SPI slave. It does not use an SPCR variable defined in the SPI.h header like the Uno rev3 which I have gotten to work. The problem is that the application is time sensitive and I suspect the bottleneck is SPI speed. (I'm trying to sync lights to audio so even the minutest difference will be noticeable).
I then tried to access the memory address directly as specified in the RA4M1 hardware manual which the Uno r4 uses. (SPCR@ 0x40072000) Hardware-Man. Github-Header. This was done by:
#include<stdint.h>
#define R_SPI0_SPCR_MSTR_Pos (3UL) /*!< MSTR (Bit */
#define R_SPI0_SPCR_MSTR_Msk (0x8UL) /*!< MSTR (Bitfield-Mask: */
uint32_t *test;
void setup() {
Serial.begin(9600);
scanf("0x40072000",test);
*test &= ~(R_SPIO_SPCR_MSTR_Msk);
}
void loop() {
scanf("0x40072000",test);
Serial.println(*test,BIN);
}
This results in no change to the println() output regardless of the bit cleaning.
I have also tried to use the official renesas libraries but I am even further out of my depths there.
#include <Arduino.h>
#include "bsp_api.h"
#include "r_spi.h"
#include "r_sci_spi.h"
#include "r_spi_api.h"
#include <stdint.h>
#include <tuple>
#include"api/HardwareSPI.h"
#include <stdint.h>
#define SPI_Controller_Addr 0x40072000
uint32_t get_register(void) {
uint32_t* addr = (uint32_t*)SPI_Controller_Addr;
return *addr;
}
spi_instance_ctrl_t _spi_ctrl;
spi_cfg_t _spi_cfg;
spi_extended_cfg_t _spi_ext_cfg;
//#define SPI_REG(channel) ((R_SPI0_Type *) ((uint32_t) R_SPI0 + \((uint32_t) R_SPI1 - (uint32_t) R_SPI0) * (channel)))
void setup(){
Serial.begin(9600);
pinMode(SCK,OUTPUT);
pinMode(MOSI,OUTPUT);
pinMode(MISO,INPUT);
//SPI config
_spi_cfg.channel=0;
_spi_ctrl.p_cfg = &_spi_cfg;
_spi_ctrl.p_callback = _spi_cfg.p_callback;
_spi_ctrl.p_context = _spi_cfg.p_context;
_spi_ctrl.p_callback_memory = NULL;
_spi_ctrl.p_regs = (R_SPI0_Type *) (0x40072000);
spi_clk_phase_t clk_phase = SPI_CLK_PHASE_EDGE_ODD;
spi_clk_polarity_t clk_polarity = SPI_CLK_POLARITY_LOW;
spi_bit_order_t bit_order = SPI_BIT_ORDER_MSB_FIRST;
_spi_cfg.operating_mode = SPI_MODE_SLAVE;
_spi_ext_cfg.spck_div = { /* Actual calculated bitrate: 12000000. */ .spbr = 1, .brdv = 0 };
_spi_cfg.clk_phase = SPI_CLK_PHASE_EDGE_ODD;
_spi_cfg.clk_polarity = SPI_CLK_POLARITY_LOW;
_spi_cfg.mode_fault = SPI_MODE_FAULT_ERROR_DISABLE;
_spi_cfg.bit_order = SPI_BIT_ORDER_MSB_FIRST;
_spi_cfg.p_transfer_tx = NULL;
_spi_cfg.p_transfer_rx = NULL;
_spi_cfg.p_context = NULL;
_spi_ctrl.p_regs->SPCR = 0; /* disable spi unit */
_spi_ctrl.p_regs->SPCR_b.MSTR = 0;
_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */
/* Power up the SPI module. */
R_BSP_MODULE_START(FSP_IP_SPI, _spi_cfg.channel);
//initalize the SPI connection
fsp_err_t err = FSP_SUCCESS;
err = R_SPI_Open(&_spi_ctrl, &_spi_cfg);
}
uint32_t b=0x40072100;
uint32_t *test;
void loop(){
scanf("0x40072000",test);
uint32_t *a=0x40072000;
//test = get_register();
Serial.println(*a,BIN);
}
Both have no effect on the register which to my understanding should be what changes to tell the controller that the SPI module should be used as a slave.
I am at the end of the road and can't think of anything else to try, thank you in advance to any who can help
Please explain what you think the above statement is doing. Because it make absolutely no sense to me.
From the scanf reference page on cplusplus.com:
int scanf ( const char * format, ... );
Read formatted data from stdin
Reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments.
The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.
I'm writing the memory address I want the pointer *test to point to- or that's the intended effect anyway
You're really not. Read the very first sentence from the excerpt.
Ah I see, thank you how about this?
#include<stdint.h>
#define R_SPI0_SPCR_MSTR_Pos (3UL) /*!< MSTR (Bit */
#define R_SPI0_SPCR_MSTR_Msk (0x8UL) /*!< MSTR (Bitfield-Mask: */
uint32_t a=0x40072000UL;
uint32_t *test;
void setup() {
Serial.begin(9600);
test = (uint32_t *)0x40072000UL;
//*test &= ~(R_SPIO_SPCR_MSTR_Msk);
*test |= (R_SPI0_SPCR_MSTR_Msk);
}
void loop() {
Serial.println(*test,BIN);
}
If this is not correct, could you please direct me to a correct method. Furthermore, this just returns 0's even after the |= which should put a 1 at bit 3.
That's more like it.
But why not just _spi_ctrl.p_regs->SPCR_b.MSTR = 0; as you do later on in your code?
My first attempt was to directly access the register myself,
_spi_ctrl.p_regs->SPCR_b.MSTR = 0; comes from the renesas library which I looked at after I had given up but I am unsure how to use it correctly.
#include <Arduino.h>
#include "bsp_api.h"
#include "r_spi.h"
#include "r_sci_spi.h"
#include "r_spi_api.h"
#include <stdint.h>
#include <tuple>
#include"api/HardwareSPI.h"
#include <stdint.h>
#define SPI_Controller_Addr 0x40072000
uint32_t get_register(void) {
uint32_t* addr = (uint32_t*)SPI_Controller_Addr;
return *addr;
}
spi_instance_ctrl_t _spi_ctrl;
spi_cfg_t _spi_cfg;
spi_extended_cfg_t _spi_ext_cfg;
//#define SPI_REG(channel) ((R_SPI0_Type *) ((uint32_t) R_SPI0 + \((uint32_t) R_SPI1 - (uint32_t) R_SPI0) * (channel)))
void setup(){
Serial.begin(9600);
pinMode(SCK,OUTPUT);
pinMode(MOSI,OUTPUT);
pinMode(MISO,INPUT);
//SPI config
_spi_cfg.channel=0;
_spi_ctrl.p_cfg = &_spi_cfg;
_spi_ctrl.p_callback = _spi_cfg.p_callback;
_spi_ctrl.p_context = _spi_cfg.p_context;
_spi_ctrl.p_callback_memory = NULL;
_spi_ctrl.p_regs = (R_SPI0_Type *) (0x40072000);
spi_clk_phase_t clk_phase = SPI_CLK_PHASE_EDGE_ODD;
spi_clk_polarity_t clk_polarity = SPI_CLK_POLARITY_LOW;
spi_bit_order_t bit_order = SPI_BIT_ORDER_MSB_FIRST;
_spi_cfg.operating_mode = SPI_MODE_SLAVE;
_spi_ext_cfg.spck_div = { /* Actual calculated bitrate: 12000000. */ .spbr = 1, .brdv = 0 };
_spi_cfg.clk_phase = SPI_CLK_PHASE_EDGE_ODD;
_spi_cfg.clk_polarity = SPI_CLK_POLARITY_LOW;
_spi_cfg.mode_fault = SPI_MODE_FAULT_ERROR_DISABLE;
_spi_cfg.bit_order = SPI_BIT_ORDER_MSB_FIRST;
_spi_cfg.p_transfer_tx = NULL;
_spi_cfg.p_transfer_rx = NULL;
_spi_cfg.p_context = NULL;
_spi_ctrl.p_regs->SPCR = 0; /* disable spi unit */
_spi_ctrl.p_regs->SPCR_b.MSTR = 1;
_spi_ctrl.p_regs->SPCR_b.SPE = 0; /* disable SPI unit */
_spi_ctrl.p_regs->SPDCR = R_SPI0_SPDCR_SPBYT_Msk; /* SPI byte access */
_spi_ctrl.p_regs->SPCMD_b[0].SPB = 7; /* spi bit width = 8 */
_spi_ctrl.p_regs->SPCR_b.SPE = 1; /* enable SPI unit */
/* Power up the SPI module. */
R_BSP_MODULE_START(FSP_IP_SPI, _spi_cfg.channel);
//initalize the SPI connection
fsp_err_t err = FSP_SUCCESS;
err = R_SPI_Open(&_spi_ctrl, &_spi_cfg);
}
uint32_t b=0x40072000;
uint32_t *test;
void loop(){
test =(uint32_t *) b;
Serial.println(*test,BIN);
}
This should set bits 4 & 6 but it doesn't seem to have any effect on the output of printLn(). (to mean they could be set or cleared and the output is unchanged)
I am well out of my depths here and I am hoping someone else has mastered how to use the minima as a slave before me
Did you try a forum search for R4 SPI slave?
2 Likes
I did but I did not find THAT, it sounds absolutely perfect! I was searching Uno rev4/Minima SPI and such, it did not return that result. Thank you so much! I'll have a play with that tomorrow
2 Likes
A point to note, there is a maximum clock limitation for the RA4M1 in SPI slave mode, which is slower than when in master mode.
See datasheet (for Rev.1.10 Sep 29, 2023 - it's on page 1358):
48.3.9 SPI Timing
Table 48.36 SPI timing (1 of 2)
Thank you so much, its too late for me to properly start reading it and I'll start tomorrow. I do appreciate the heads up however I'm using a RPi as the master so I was just gonna keep bumping up the speed until I hit a limit 
1 Like
I am incredibly grateful for your code but I would like to ask one more question...
I believe what went wrong with my code was that I was not changing the *MSTP_MSTPCRB register.
My question is: When you were creating your code, did you know that that register needed to be changed from previous experience with micro-controllers or did I miss something in the documentation (Hardware manual) that stated this.
I want to be able to just look at manuals and work it out myself in the future is all.
1 Like
I have used low-power processors before, including the Silicon Labs Gecko M4 controllers ... but I did have a bit of puzzlement before I remembered I needed to enable the modules individually. 