I am relatively new to verilog (a VHDL user), and in order to improve my skills i built my test environment using verilog (my QC use their own env).
In my env, I emulate a master that force random stimuli on the lines (i2c master).
since i didn't really want to use a real master and wanted only a 'well behaved' master, i created the following macros to provide me with the i2c communications:
`define writeChipId(addr)\
sda = 1\
#7500 sda = addr[3];\
#2500 sda = addr[2];\
#2500 sda = addr[1];\
#2500 sda = addr[0];\
#2500;
`define writeData(data)\
sda = data[7]\
#2500 sda = data[6];\
#2500 sda = data[5];\
#2500 sda = data[4];\
#2500 sda = data[3];\
#2500 sda = data[2];\
#2500 sda = data[1];\
#2500 sda = data[0];\
#2500 sda = 1;\
#2500; // time for the slave to answer
`define readData\
#sda = 1\
#20000 sda = 0;\
#2500; // master always answer ACK
my problem is that, when i try to use these macros i get a compilation errors (using modelsim) saying i have a syntax error and i have unexpected '[' that should be ';' for using the chipID macro and having unexpected '#' that should be ';' when using the read\ write macros.
the usages i try (and fail) are
`writeChipId(`chipID)
and
`writeData(rndData)
and
`readData
last, but not least: if i write the same lines without the macro in my code, it compiles perfectly (only tried in one place, don't want to do it for the 12 other places i'll need these macros...)
anyone have a clue what is the problem? i've been trying to play with the macros with no luck and also verified they have no white spaces stuck in the middle.
also looked for multi-line macro examples and found similar things to what I did that didn't give an answer.
thanks in advance to all repliers
edit
something i forgot saying: when i take the macro and remove the input and use const values instead of the input, it works fine.
The syntax for a `define requires a space after the macro identifier/arguments.
`define writeChipId(addr) \
sda = 1;\
#7500 sda = addr[3];\
#2500 sda = addr[2];\
#2500 sda = addr[1];\
#2500 sda = addr[0];\
#2500;
As Greg pointed out, this really calls for using a task.
task writeChipId(input [3:0] addr);
sda = 1;
#7500 sda = addr[3];
#2500 sda = addr[2];
#2500 sda = addr[1];
#2500 sda = addr[0];
#2500;
endtask
ok, solution found:
the first line of each macro should also have semicolon (;), also - the use of parameter for the chipID is hard on the verilog, this was solved by putting the input into a reg and using the reg's bits.
i didn't come across this problem the previous time I used macros because of another mistake I made - I defined the macro of the constant to have semicolon (meaning `define ADD 32'h0;) and when I used it it inserted the ; to the line and seemed OK.
Related
I used "-machine dumpdtb=dtb.dtb" in qemu command to extract dtb file of the arm 'virt' machine. Then I converted the dtb file to dts file using dtc. And I tried to make that dts file backto dtb. But I'm seeing a warning message like this (only showing the first warning).
dtb.dts:284.3-21: Warning (clocks_property): /pl061#9030000:clocks: cell 0 is not a phandle reference
The warning comes from the line in the dts
pl061#9030000 {
phandle = <0x8003>;
clock-names = "apb_pclk";
clocks = <0x8000>; <==== this line
interrupts = <0x00 0x07 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
compatible = "arm,pl061\0arm,primecell";
reg = <0x00 0x9030000 0x00 0x1000>;
};
I've looked at Documentation/devicetree/bindings/gpio/pl061-gpio.yaml but there is no explanation about the property clocks. I guess it's the clock frequency for the gpio but somehow the dtc program thinks it is a phandle. and I couldn't find any use of 'clocks' in the pl061 driver. Can I just safely ignore that error?
This is a phandle to the /apb-pclk node elsewhere in the dtb. The "clocks" property is part of the "arm,primecell" binding, documented here:
https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/primecell.txt
Here is my frankensteined code, the error arises when i'm defining gps_module on line 12. I'm attaching pico pin 4 to the SDA on the GPS, pin 5 to the SCL, ground, and power
from machine import Pin, UART, I2C
#Import utime library to implement delay
import utime, time
sda_pin = machine.Pin(4)
scl_pin = machine.Pin(5)
# Create an I2C object out of our SDA and SCL pin objects
gps_module = machine.I2C(sda=sda_pin, scl=scl_pin)
print(gps_module)
#Used to Store NMEA Sentences
buff = bytearray(255)
TIMEOUT = False
#store the status of satellite is fixed or not
FIX_STATUS = False
Try 1 or 0 in the declaration
gps_module = machine.I2C(1, sda=sda_pin, scl=scl_pin)
https://docs.micropython.org/en/latest/library/machine.I2C.html#constructors
class machine.I2C(id, *, scl, sda, freq=400000)
Construct and return a new I2C object using the following parameters:
id identifies a particular I2C peripheral. Allowed values for depend
on the particular port/board
scl should be a pin object specifying the pin to use for SCL.
sda should be a pin object specifying the pin to use for SDA.
freq should be an integer which sets the maximum frequency for SCL.
I have compiled an image with buildroot. I want to work with I2C2 which is located in P9.19 and P9.20 ( SCL and SDA). I have connected the BBB I2C2 to a kw40z - NXP controller. I have added pull up to SDA and SCL, shared ground and connected both SCL and SDA to each other. I do see /dev/i2c-2
I2C2 does not work. I tried i2cdetect -r 2 and also a C program but I am getting timeout.
My questions are:
Does I2C2 is enabled or should I add the I2C2 device tree overlay from here:
If so, I compile the above dts fragment into dtbo ( using the dtc compiler)
How do i tell buildroot in beagle bone to load that dtbo?
I read that buildroot and even Debian does not support cape manager.
So it should be static.
Does any one managed to work with I2C2 without overlay? or is it a must?
Thanks!
Problem solved for i2c1 and i2c2
I added the two fragments into the bone-common.dtsi
for both I2C1 and I2C2 ( this is I2C1 for example)
under the pin mux
&am33xx_pinmux {
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
0x158 (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE2) /* i2c1_sda */
0x15c (SLEWCTRL_SLOW | PIN_INPUT_PULLUP | MUX_MODE2) /*i2c1_scl */>;
};
And the node itself in am335x-boneblack.dts
&i2c1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
/* this is the configuration part */
clock-frequency = <100000>;
#address-cells = <1>;
#size-cells = <0>;
};
Also , no need for external pull-up when its is internally of course.
The pins are 17 - scl and 18 sda
I am trying to drive a EEPROM Chip 25LC256 with a STM32F469I-DISCO but can't achieve it.
I have tried to make my own function with HAL API bases but apparently something is wrong : I don't know if I write datas on the chip since I can't read it. Let me explain more.
So my chip is a DIP 25LC256 (DS is above is you wish). PINs HOLD and WP of EEPROM are tied to VCC (3.3V). PIN CS is connected to PH6 (ARD_D10 on board) and is managed by the software. PIN SI and PIN SO are respectively connected to PB15 (ARD_D11) and PB14 (ARD_D12) with the right alternate function (GPIO_AF5_SPI2). PIN SCK is also connected to PD3 (ADR_D13).
Here is my SPI configuration code :
EEPROM_StatusTypeDef ConfigurationSPI2(SPI_HandleTypeDef *spi2Handle){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
GPIO_InitTypeDef gpioInit;
//// SCK [PD3]
gpioInit.Pin = GPIO_PIN_3;
gpioInit.Mode = GPIO_MODE_AF_PP;
gpioInit.Pull = GPIO_PULLDOWN;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
gpioInit.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOD, &gpioInit);
//// MOSI [PB15]
gpioInit.Pin = GPIO_PIN_15;
gpioInit.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &gpioInit);
//// MISO [PB14]
gpioInit.Pin = GPIO_PIN_14;
gpioInit.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &gpioInit);
//// CS [PH6]
gpioInit.Pin = GPIO_PIN_6;
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOH, &gpioInit);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, GPIO_PIN_SET);
//// SPI2
__HAL_RCC_SPI2_CLK_ENABLE();
spi2Handle->Instance = SPI2;
spi2Handle->Init.Mode = SPI_MODE_MASTER;
spi2Handle->Init.Direction = SPI_DIRECTION_2LINES;
spi2Handle->Init.DataSize = SPI_DATASIZE_8BIT;
spi2Handle->Init.CLKPolarity = SPI_POLARITY_LOW;
spi2Handle->Init.CLKPhase = SPI_PHASE_1EDGE;
spi2Handle->Init.NSS = SPI_NSS_SOFT;
spi2Handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
spi2Handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
spi2Handle->Init.TIMode = SPI_TIMODE_DISABLE;
spi2Handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE ;
spi2Handle->Init.CRCPolynomial = 7;
if(HAL_SPI_Init(spi2Handle) != HAL_OK){
return EEPROM_ERROR;
}
return EEPROM_OK;
}
And two functions allowing respectively (and theorically) to WRITE and READ into the the chip :
Write Function :
EEPROM_StatusTypeDef WriteEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *txBuffer, uint16_t size, uint16_t addr){
uint8_t addrLow = addr & 0xFF;
uint8_t addrHigh = (addr >> 8);
uint8_t wrenInstruction = WREN_EEPROM; // Value : 0x06
uint8_t buffer[32] = {WRITE_EEPROM, addrHigh, addrLow}; //Value : 0x02
for(uint i = 0 ; i < size ; i++){
buffer[3+i] = txBuffer[i];
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
if(HAL_SPI_Transmit(spi2Handle, &wrenInstruction, 1, TIMEOUT_EEPROM) != HAL_OK){
return EEPROM_ERROR;;
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
if(HAL_SPI_Transmit(spi2Handle, buffer, (size + 3), TIMEOUT_EEPROM) != HAL_OK){
return EEPROM_ERROR;
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
return EEPROM_OK;
}
Read Function :
EEPROM_StatusTypeDef ReadEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *rxBuffer, uint16_t size, uint16_t addr){
uint8_t addrLow = addr & 0xFF;
uint8_t addrHigh = (addr >> 8);
uint8_t txBuffer[3] = {READ_EEPROM, addrHigh, addrLow};
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
HAL_SPI_Transmit(spi2Handle, txBuffer, 3, TIMEOUT_EEPROM);
HAL_SPI_Receive(spi2Handle, rxBuffer, size, TIMEOUT_EEPROM);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
return EEPROM_OK;
}
I know my function are not very "beautiful" but it was a first attempt. In my main, I have tried in the first place to write into the chip the data "0x05" at the 0x01 adress then to read this data back :
uint8_t bufferEEPROM[1] = {5};
uint8_t bufferEEPROM2[1] = {1};
WriteEEPROM(&spi2Handle, bufferEEPROM, 1, 0x01);
ReadEEPROM(&spi2Handle, bufferEEPROM2, 1, 0x01);
I have an oscilloscope so since it didn't work (monitoring with STM Studio) I visualized the CLK and SI PINs then CLK and SO PINs (can only see two channel at the same time) :
As you can see, with the first picture that shows CLK (yellow) and SI (or MOSI) in blue, I have all the data expected : The WRite ENable instruction then the WRITE instruction. Following the ADDRESS, then the DATA.
After that, the Read Function starts. First the READ instruction and the ADDRESS where I want to fetch the data. The last 8 bits are supposed to be the data stored at the address (0x01 in this case). Something happens on SI PIN but I guess this is because the HAL_SPI_Receive() function actually calls HAL_SPI_TransmitReceive() with my array bufferEEPROM2 as parameter (that's why we can se 0b00000001). And so it is because of my SPI configuration parameter (Full-duplex).
Anyway, theorically I am supposed to see 0b00000101 on SO PIN but as you can see in the second picture.... nothing.
I have tried to change gpioInit.Pull for SO PIN on PULLUP and PULLDOWN but nothing changed. NOPULL is because that's the last thing I have tried.
The thing is I don't know where to start. My transmission seems to work (but is it actually ?). Is there anything wrong with my initialization ? Acutally my main question would be : why I don't receive any data from my EEPROM ?
Many thanks !
Write operations need some time to complete (your datasheet says 5 ms on page 4), during that time no operation other than read status is possible. Try polling the status register with the RDSR (0x05) opcode to find out when it becomes ready (bit 0). You could also check the status (bit 1) before and after issuing WREN to see if it was successful.
So the problem is now solved. Here are the improvements :
There was actually two issues. The first one and certainly the most important is, as berendi stated, a timing issue. In my WRITE function I didn't let the time for the EEPROM to complete its write cycle (5 ms on datasheet). I added the following code line at the end of all my WRITE functions :
HAL_Delay(10); //10 ms wait for the EEPROM to complete the write cycle
The delay value could be less I think if time is preicous (theorically 5ms). I didn't test below 10 ms though. An other thing. With the oscilloscope I also saw that my Chip Select used to went HIGH in the middle of my last clock edge. I could not say if this could also imply some issues since that's a thing I solved in the first place by adding a code line before HAl_Delay(10). All my SPI transmission functions finishes this way now :
while(HAL_GPIO_ReadPin(CLK_PORT, CLK_PIN) == GPIO_PIN_SET){
}
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
HAL_Delay(10);
This way I have the proper pattern and I can write in the EEPROM and read back what I wrote.
NB : A last thing that made me goes deeper into my misunderstanding of the events : since my write functions didn't work, I focused on STATUS REGISTER write and read function (in order to solve this step by step). The write function didn't work either and in fact it was because the WRENbit wasn't set. I though (wrong one) that the fact to write into the STATUS REGISTER didn't ask also to set WREN like the WRITE functions into the memory ask to. Actually, it is also necessary.
Thanks for the help !
I work on Atom-32bit-intel, I have to port MicroC OS II, so there is no code to make any configuration on the Atom (No GDT, no LDT...):
my question is more about the state of the Atom-32bit after a reset, is the Atom in protecte mode or not ? and the most important how do i check which mode is it (which registers have to be checked nad how)?
Remark:
The CR0.PE = 1 (I checked it), is that enough to prove that the Atom is in protected mode ?
************ UPDATE : *****************
/*Read the IDTR*/
sidt (idt_ptr)
/*Read the GDTR*/
sgdt (gdt_ptr)
So I tried just to use IDT's address to link my ISR to the IDT :
fill_interrupt(ISR_Nbr,(unsigned int) isr33, 0x08, 0x8E);
static void fill_interrupt(unsigned char num, unsigned int base, unsigned short sel, unsigned char flags)
{
unsigned short *Interrupt_Address;
/*address = idt_ptr.base + num * 8 byte*/
Interrupt_Address = (unsigned short *)(idt_ptr.base + num*8);
*(Interrupt_Address) = base&0xFFFF;
*(Interrupt_Address+1) = sel;
*(Interrupt_Address+1) = (flags>>8)&0xFF00;
*(Interrupt_Address+1) = (base>>16)&0xFFFF;
}
my ISR a imple one :
isr33:
nop
nop
cli
push %ebp //save the context to swith back
mov %esp,%ebp
pop %ebp //Return to the calling function
sti
ret
Chapter 9 of volume 3 of the Intel Software Developer's Manual says that the reset value of CR0 is 60000010H. As you can see, bit 0, aka PE, is clear.
Regardless, you can setup the descriptor tables in Protected Mode as well as in Real Mode. You just have to be more careful about it.
I suggest you check if the BIOS or OS are setting this bit at a stage before you read it.
Atom is x86 instruction set, and as such, should be starting in real mode for compatibility. I don't have one on hand to test with though.
Resolved, I use N450 Atom board, it has already a BIOS, the BIOS configures the board in Protected Mode.